Shell 运维组合案例¶
下面案例重点展示分析顺序。字段位置必须以现场命令输出和日志格式为准,不要直接复制后假设所有系统一致。
HTTP 状态码统计¶
假设 Nginx combined log 的状态码是第 9 字段:
先抽样确认字段:
日志格式变化后第 9 字段可能不再是状态码,生产最好输出 JSON 并用结构化工具处理。
访问最多的客户端 IP¶
反向代理场景 $1 可能是 LB 地址,真实客户端取决于可信代理和日志中的 X-Forwarded-For 处理;不能仅凭结果封禁 IP。
TCP 连接状态¶
查看远端连接最多的地址时要先确认 ss 输出列和 IPv6 格式。简单按冒号切割会把 IPv6 地址拆坏。
进程 CPU 和内存 Top N¶
ps -eo pid,ppid,user,%cpu,%mem,rss,etime,cmd --sort=-%cpu | head -20
ps -eo pid,ppid,user,%cpu,%mem,rss,etime,cmd --sort=-rss | head -20
ps --sort 是 GNU/procps 常用能力,macOS/BSD 参数不同。瞬时 CPU 只用于定位候选,还要结合持续采样、线程、应用指标和最近变更。
文件系统使用率告警候选¶
df -P \
| awk 'NR>1 {
used=$5
sub(/%$/, "", used)
if (used >= 80) print used "%", $6
}' \
| sort -nr
挂载点包含空格时字段处理会复杂;自动化监控优先使用稳定指标采集,而不是周期性解析人类可读命令。
日志错误 Top N¶
grep -E 'ERROR|Exception|timeout|connection refused' app.log \
| sed -E 's/request_id=[^ ]+/request_id=<id>/g' \
| sort \
| uniq -c \
| sort -nr \
| head -20
如果每行含时间、线程和随机 ID,必须先归一化动态字段,否则每行都不同,uniq -c 没有意义。归一化也可能把不同错误合并,最终仍需查看原始上下文和堆栈。
按时间范围查看 systemd 日志¶
journalctl -u app.service \
--since '2026-08-24 10:00:00' \
--until '2026-08-24 10:30:00' \
--no-pager \
| grep -Ei 'error|exception|timeout'
这里 grep -E 替代旧的 egrep;-i 忽略大小写。先确认主机和日志时区再与告警时间对应。
安全修改配置¶
cp -a app.conf "app.conf.bak.$(date +%Y%m%d%H%M%S)"
sed 's/^log_level=.*/log_level=INFO/' app.conf > app.conf.new
diff -u app.conf app.conf.new
appctl check-config app.conf.new
mv app.conf.new app.conf
systemctl reload app
systemctl status app --no-pager
关键顺序是备份、生成新文件、查看差异、语法检查、替换、reload、运行验证。sed -i 只能缩短命令,不能替代变更验证和回滚。
查找大日志¶
-xdev 限制在当前文件系统,NUL 分隔安全处理带空格文件名。发现大日志后应修复轮转和日志量,不要在进程仍持有文件时直接删除;已删除但空间未释放可用 lsof +L1 检查。
拆开验证流水线¶
复杂命令应逐段检查:
grep -E 'ERROR|timeout' app.log | head
grep -E 'ERROR|timeout' app.log | sed -E '...' | head
grep -E 'ERROR|timeout' app.log | sed -E '...' | sort | uniq -c | head
每加入一段就确认输入、输出和行数,能快速发现正则不匹配、字段位置错误、locale 排序或过度归一化。