Shell 三剑客与自动化脚本实践

运维的日常工作(看日志、查状态、做巡检)如果全靠手工敲命令,一天什么都干不了。把重复操作沉淀成脚本 + 定时任务,是运维从”救火”走向”自动化”的分水岭。这篇整理三剑客和 Shell 脚本的实战用法。

一、三剑客:grep / sed / awk

grep:过滤文本

1
2
3
4
grep -n "ERROR" app.log          # 带行号过滤
grep -v "^#" nginx.conf # 排除注释行
egrep -n "ERROR|WARN" app.log # 多关键词
grep -A5 "Exception" app.log # 匹配后 5 行(看异常堆栈必备)

sed:按行过滤与批量修改

sed 是流编辑器,按行处理、无需打开文件,脚本化修改配置的核心工具。

1
2
3
4
sed -n '10,20p' nginx.conf       # 打印 10-20 行
sed -i 's/8080/8081/g' nginx.conf # 全局替换并写回(-i 原地修改)
sed -i '/^#/d' nginx.conf # 删除注释行
sed -n '/^server/,/}/p' nginx.conf # 区间匹配

两个纪律:①-i 前先备份(cp xxx xxx.bak),改配置类文件尤其如此;②替换匹配尽量精确,避免误伤。

awk:取行取列与统计

1
2
3
4
awk '{print $1, $3}' access.log          # 取第 1、3 列
awk '$9 == 500 {print $1}' access.log # 过滤 500 状态码的行
awk '{count[$1]++} END{for (k in count) print k, count[k]}' access.log | sort -k2 -rn | head
# 统计每个 IP 的请求次数,前 10 名(日志分析高频用法)

二、Shell 脚本规范

脚本骨架

1
2
3
4
5
#!/bin/bash
# 注释头:脚本用途、作者、修改记录(团队规范)
set -e # 出错即停(排障友好)
# 变量:统一大写或用小写下划线
LOG_DIR="/data/logs"

变量与传参

1
2
3
4
5
6
7
8
# 特殊变量:$0 脚本名 $1-$9 位置参数 $# 参数个数 $? 上条命令退出码
# 判断:判断上一条命令是否成功就看 $?
ping -c1 www.baidu.com >/dev/null 2>&1 && echo "通" || echo "不通"

# 默认值(生产常用:环境变量没设就用默认)
PORT=${PORT:-3306}
# 强制必须设置:没传参数就报错退出
[ $# -lt 1 ] && echo "用法: $0 参数1" && exit 1

条件与循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 数值/字符串/文件判断
[ $FREE -lt 10 ] && echo "磁盘空间不足" # 数值比较
[ -f /etc/nginx/nginx.conf ] && echo "存在" # 文件判断
[ -z "$VAR" ] && echo "变量为空"

# 循环
for ip in 10.0.8.11 10.0.8.12; do ping -c1 -W1 $ip >/dev/null && echo "$ip 通" || echo "$ip 不通"; done
while read line; do echo "$line"; done < list.txt

# case 多路选择(服务操作脚本常用)
case "$1" in
start) systemctl start nginx ;;
stop) systemctl stop nginx ;;
*) echo "用法: $0 start|stop" ;;
esac

函数与局部变量

1
2
3
# 函数内的变量必须用 local,防止污染全局(这也是排查"变量莫名被改"的常见元凶)
log_info() { local msg="$1"; echo "[INFO] $(date '+%F %T') $msg"; }
check_disk() { local use=$(df -h / | awk 'NR==2{print $5}' | tr -d '%'); [ "$use" -gt 80 ] && echo "根分区使用率 ${use}%"; }

三、定时任务:crontab

五段式:分 时 日 月 周 命令

1
2
3
4
5
6
7
8
9
10
crontab -e
# 每天凌晨 2 点备份
0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
# 每 10 分钟巡检一次
*/10 * * * * /opt/scripts/check.sh
# 每周日凌晨 3 点清理
0 3 * * 0 /opt/scripts/cleanup.sh

crontab -l # 查看
crontab -r # 删除(慎用)

定时任务三个高频坑:

  1. 脚本里的环境变量(PATH)是精简的:在 crontab 里直接写 rsyncpython3 可能 command not found——脚本开头显式定义或用绝对路径;
  2. 输出重定向必须写:不写 >> log 2>&1,脚本报错内容会发到系统邮箱(没人看),排障全靠猜;
  3. 任务没执行先查三件事crontab -l 任务在不在、脚本权限(chmod +x)、手动跑一遍有没有报错。

四、一个完整的巡检脚本案例

把”每天的磁盘/内存/负载巡检”沉淀成脚本,配 crontab 每天跑,结果统一写到日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
# 日常巡检:磁盘、内存、负载
LOG="/var/log/ops/daily-check.log"
TS=$(date '+%F %T')

echo "===== $TS 巡检开始 =====" >> $LOG

# 磁盘使用率 TOP 检查
df -h | awk 'NR>1 && $5+0 > 80 {print "磁盘告警: " $0}' >> $LOG

# 内存
free -h | awk 'NR==2 {print "内存: 总量"$2" 已用"$3" 可用"$7}' >> $LOG

# 负载(超过核数阈值提醒)
LOAD=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1)
echo "负载: $LOAD" >> $LOG
1
0 8 * * * /opt/scripts/daily-check.sh

脚本化的收益是复利式的:每次把重复操作写成脚本 + 定时任务,后面所有机器都能复用,也逼着自己把每一步操作想清楚——这正是排查和自动化能力一起提升的过程。