2026.05.20 | youres | 9次围观
为什么要学Shell脚本自动化运维
每天手动登录十几台服务器查日志、清磁盘、重启服务——这是很多运维新手的日常。Shell脚本能把这些都变成定时自动任务,你只需要写好一次,剩下的交给cron。
自动化运维的核心价值就三点:省时间、减错误、可复用。一个写好测好的脚本,在100台服务器上跑和在1台上跑,成本几乎一样。
Shell脚本基础:10分钟上手
变量与参数
# 定义变量(注意等号前后不能有空格)
LOG_DIR="/var/log"
APP_NAME="nginx"
# 使用变量
echo "清理 $APP_NAME 的日志目录: $LOG_DIR"
# 特殊变量
echo "脚本名: $0"
echo "第一个参数: $1"
echo "参数个数: $#"
echo "所有参数: $@"
条件判断
# 判断目录是否存在
if [ ! -d "$LOG_DIR" ]; then
mkdir -p "$LOG_DIR"
echo "目录已创建"
fi
# 判断进程是否运行
if pgrep -x "nginx" > /dev/null; then
echo "Nginx 正在运行"
else
echo "Nginx 未运行,尝试启动..."
systemctl start nginx
fi
循环:批量操作的核心
# for循环:批量重启服务
for service in nginx mysql redis; do
echo "重启 $service ..."
systemctl restart $service
done
# while循环:读取文件逐行处理
while IFS= read -r line; do
echo "处理: $line"
done < server_list.txt
自动化运维5大核心场景
场景1:日志轮转与自动清理
日志文件最容易把磁盘写爆。与其每次手动rm,不如写个脚本定时跑。
#!/bin/bash
# log_clean.sh - 日志自动清理脚本
LOG_DIR="/var/log/nginx"
MAX_DAYS=7
MAX_SIZE_MB=500
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始日志清理..."
# 删除7天前的日志文件
find "$LOG_DIR" -name "*.log" -mtime +$MAX_DAYS -delete -print | wc -l | xargs echo "已删除旧日志文件数:"
# 如果日志总大小超过500MB,压缩最老的日志
LOG_SIZE=$(du -sm "$LOG_DIR" | cut -f1)
if [ "$LOG_SIZE" -gt $MAX_SIZE_MB ]; then
echo "日志目录超过 ${MAX_SIZE_MB}MB,开始压缩..."
find "$LOG_DIR" -name "*.log" -mtime +1 -exec gzip {} \;
fi
echo "日志清理完成"
场景2:数据库自动备份
#!/bin/bash
# db_backup.sh - MySQL自动备份脚本
BACKUP_DIR="/data/backup/mysql"
DATE=$(date '+%Y%m%d_%H%M%S')
MYSQL_USER="backup_user"
MYSQL_PASS="your_password"
KEEP_DAYS=7
mkdir -p "$BACKUP_DIR/$DATE"
# 获取所有数据库列表
databases=$(mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema)")
for db in $databases; do
echo "备份数据库: $db"
mysqldump -u"$MYSQL_USER" -p"$MYSQL_PASS" --single-transaction "$db" | gzip > "$BACKUP_DIR/$DATE/${db}_$DATE.sql.gz"
done
# 删除7天前的备份
find "$BACKUP_DIR" -type d -mtime +$KEEP_DAYS -exec rm -rf {} + 2>/dev/null
echo "备份完成,保存位置: $BACKUP_DIR/$DATE"
场景3:服务健康监控与自愈
#!/bin/bash
# health_check.sh - 服务健康检查脚本
# 当服务异常时自动重启,并发送告警
SERVICES=("nginx" "mysql" "redis-server")
ADMIN_EMAIL="admin@example.com"
for svc in "${SERVICES[@]}"; do
if ! systemctl is-active --quiet "$svc"; then
echo "[$(date)] 警告: $svc 服务异常,尝试重启..." | tee -a /var/log/health_check.log
systemctl restart "$svc"
sleep 3
if systemctl is-active --quiet "$svc"; then
echo "[$(date)] $svc 重启成功" | tee -a /var/log/health_check.log
else
echo "[$(date)] $svc 重启失败,请人工介入!" | tee -a /var/log/health_check.log
# 发送告警邮件(需要配置mailx)
# echo "$svc 重启失败" | mail -s "服务告警" "$ADMIN_EMAIL"
fi
fi
done
场景4:磁盘空间监控告警
#!/bin/bash
# disk_alert.sh - 磁盘空间监控
THRESHOLD=80
ADMIN_EMAIL="admin@example.com"
df -h | awk 'NR>1 {print $5, $6}' | while read usage mountpoint; do
# 去掉百分号
percent=${usage%\%}
if [ "$percent" -ge "$THRESHOLD" ]; then
echo "[$(date)] 告警: 分区 $mountpoint 使用率 ${usage},超过阈值 ${THRESHOLD}%"
# 找出最大的10个文件
echo "--- 占用空间最大的10个文件 ---"
find "$mountpoint" -type f -exec du -h {} + 2>/dev/null | sort -rh | head -10
fi
done
场景5:批量服务器巡检
#!/bin/bash
# server_inspect.sh - 批量服务器巡检
# 需要配置SSH免密登录
SERVERS=("192.168.1.10" "192.168.1.11" "192.168.1.12")
REPORT_FILE="/tmp/server_inspect_$(date '+%Y%m%d').txt"
echo "========== 服务器巡检报告 $(date) ==========" > "$REPORT_FILE"
for host in "${SERVERS[@]}"; do
echo "" >> "$REPORT_FILE"
echo "--- $host ---" >> "$REPORT_FILE"
ssh "$host" '
echo "主机名: $(hostname)"
echo " uptime: $(uptime)"
echo " 磁盘: $(df -h / | tail -1)"
echo " 内存: $(free -h | grep Mem)"
echo " 负载: $(cat /proc/loadavg)"
echo " 异常进程: $(ps aux --sort=-%cpu | head -5 | tail -4)"
' >> "$REPORT_FILE" 2>&1
done
echo "巡检报告已生成: $REPORT_FILE"
把脚本加入定时任务(cron)
脚本写好了,让它在后台按时跑才是真正自动化。编辑crontab:
# 日志清理:每天凌晨2点执行
0 2 * * * /opt/scripts/log_clean.sh >> /var/log/log_clean.log 2>&1
# 数据库备份:每天凌晨3点执行
0 3 * * * /opt/scripts/db_backup.sh >> /var/log/db_backup.log 2>&1
# 服务健康检查:每5分钟执行一次
*/5 * * * * /opt/scripts/health_check.sh >> /var/log/health_check.log 2>&1
# 磁盘监控:每小时执行一次
0 * * * * /opt/scripts/disk_alert.sh >> /var/log/disk_alert.log 2>&1
# 批量巡检:每周一早上8点
0 8 * * 1 /opt/scripts/server_inspect.sh
Shell脚本最佳实践
- 加
set -e:脚本遇到错误立即退出,避免错误累积 - 所有路径用绝对路径:防止cron执行时环境变量不同导致找不到命令
- 关键步骤写日志:出问题时有迹可循,用
echo "$(date) 操作步骤" >> logfile - 敏感信息不要硬编码:数据库密码等放在独立的配置文件里,权限设为600
- 先测试再上生产:在测试服务器跑通后再部署,尤其是删除操作
- 脚本开头指定解释器:
#!/bin/bash而不是#!/bin/sh,确保功能完整
常见坑与避坑指南
坑1:Windows换行符
在Windows编辑的脚本传到Linux会报^M: bad interpreter错误。用dos2unix script.sh转换,或者直接在Linux上编辑。
坑2:变量不加引号
路径含空格时,$LOG_DIR/*.log会展开失败。正确写法:"$LOG_DIR"/*.log,双引号包住变量,但不包通配符。
坑3:cron环境变量缺失
cron执行时的PATH很精简,脚本里用命令最好写绝对路径,比如/usr/bin/find而不是find。
内链相关阅读
- Linux服务器安全配置基线:从账户到审计的完整Checklist - 服务器安全加固必读
- 服务器自动备份方案:rsync异地增量备份实战指南 - 备份策略深度解析
- 服务器监控工具推荐:10款主流开源与商业软件选型指南 - 监控体系搭建参考
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论