生产环境巡检脚本必须用 df -P、systemctl is-active 配合 pgrep/ss、journalctl 加 --no-pager 和冗余时间范围,并校验 root 权限;90% 失败源于基础命令在非交互环境行为不一致或权限缺失。

直接上结论:别写“全能巡检脚本”,先确保 df、systemctl is-active、journalctl --since 这三个命令在你所有目标机器上能稳定返回结果——90% 的失败都卡在这一步。
为什么 df -h 在 cron 里输出格式会乱?
因为 df -h 在非交互终端下可能省略列头、单位缩写不一致,甚至因 locale 导致千位分隔符干扰解析。生产环境必须用 df -P(POSIX 格式),它强制固定字段顺序和无单位数值。
- 错例:
df -h / | awk 'NR==2 {print $5}'—— 某些系统df -h第二行是空行或标题,NR==2直接取错 - 正解:
df -P / | awk 'NR==2 {gsub(/%/,"",$5); print $5}',-P保证第二行必为数据,gsub去掉 % 符号避免字符串比较 - 加超时防卡死:
timeout 8 df -P /,避免磁盘 hang 住整个脚本
systemctl is-active 返回值不可信?
它只反映 systemd 记录的“服务单元状态”,不等于进程真实存活。比如 nginx master 进程还在,但所有 worker 已崩溃,systemctl is-active nginx 仍返回 active。
- 真存活检查要两步:先确认 unit 状态,再用
pgrep -x nginx看是否有实际进程 - 别用
ps aux | grep nginx—— 它会匹配到自己这条 grep 命令,导致误判 - 轻量替代:
ss -tlnp 2>/dev/null | grep ':80' | grep -q nginx,验证端口是否被 nginx 真实监听(需 root 权限)
日志扫描总漏掉刚发生的错误?
journalctl --since "1 hour ago" 看似合理,但 journal 日志轮转(systemd-journald 配置)可能让旧日志被压缩归档,--since 查不到;更糟的是,journalctl 默认带分页器,在脚本中会阻塞等待输入。
- 必须加
--no-pager,否则脚本卡死 - 时间范围要冗余:用
--since "2 hours ago",并限制条数:journalctl --since "2 hours ago" --no-pager -n 200 - 关键词要覆盖变体:
grep -i -E "(fail|error|killed|oom|panic|refused)",注意大小写和拼写差异 - 关键服务单独查:
journalctl -u sshd --since "30 minutes ago" --no-pager | grep -i "failed",比扫全量更准
最常被跳过的其实是权限校验:脚本开头没加 [[ $EUID -ne 0 ]] && exit 1,导致非 root 用户执行时,systemctl、ss -p、journalctl -u 全部静默失败,你还以为“一切正常”。











