综合 用 Codex 写 Linux 巡检脚本:默认只读是边界,--self-test 才是验收

2026-09-12 21:02:58

用 Codex 写 Linux 巡检脚本:默认只读是边界,--self-test 才是验收

目标很具体:一个默认只读、可配置、能同时输出文本和 JSON 报告、有明确退出码和自测模式的 Linux Bash 主机健康巡检脚本。

需求先列清楚:

  1. 支持多种信息源:/procdfpssystemctljournalctlss
  2. 兼容 Ubuntu、Debian、Rocky Linux、AlmaLinux、CentOS Stream;
  3. 处理命令缺失、权限不足、systemd 不可用等异常分支;
  4. 阈值、退出码和机器可读报告作为自动化接口;
  5. 最重要的安全边界:巡检脚本默认不应该修改系统——不修改配置、不重启服务、不清理文件、不调用 sudo

第 5 条决定了整个脚本的形态。采集只能读,任何修复动作都不在脚本职责内。

采集项与对应命令

采集项命令 / 来源
1 分钟归一化负载/proc/loadavg
内存使用率/proc/meminfoMemTotal / MemAvailable
磁盘空间df -P
inodedf -Pi
失败的 systemd 单元systemctl --failed
僵尸进程ps
最近 1 小时高优先级日志journalctl
最近 24 小时 OOMjournalctl
TCP 监听端口数量ss -lntH

内存看的是 MemAvailable 占比,不是 free 值,这点直接影响告警准确度。

三层架构

脚本拆成采集、判断、报告三层。采集层只负责拿到原始数据并标准化,判断层只吃标准化结果,报告层只消费判断结果。这样文本和 JSON 两条输出路径的结论必然一致,不会出现文本显示告警、JSON 里却写着正常的尴尬。

退出码约定

退出码固定,不随参数变化:

  • 0 正常
  • 1 告警
  • 2 严重
  • 3 脚本错误

参数必须校验,告警阈值必须小于严重阈值,否则以 3 退出。JSON 必须正确转义,能被标准解析器读取。

set -euo pipefail 不是万能药

严格模式用 set -euo pipefail-u 帮忙发现未定义变量,pipefail 让管道中间命令的失败也能传递出来。

但严格模式不是魔法。if!|| 和命令替换这几类场景里,返回码仍要显式处理。所以对 systemctljournalctl 单独判断:读取失败时显示 INFO / N/A,而不是错误地显示 OK / 0。把这两个命令的失败当成"一切正常",是这类脚本最容易踩的坑。

「无法检查」和「检查正常」必须分开

关键设计就一句话:把"无法检查"和"检查正常"严格分开。

  • 日志权限不足,返回 N/A
  • systemd 不可用时,不能误报正常。

一个没有 systemd 的容器里跑巡检,如果输出"0 个失败单元、一切正常",这份报告比没有报告更危险。

--demo 与 --self-test

提供 --demo 匿名演示模式,用内置的假数据生成报告,方便在没数据的环境里先看报告格式长什么样。

提供 --self-test 自测模式,脚本自己验证阈值比较、退出码映射、JSON 转义这些内部逻辑,不依赖宿主机当前状态。

验收方法

在目标机器上按顺序跑:

# 1. 语法检查
bash -n healthcheck.sh

# 2. 内置自测
./healthcheck.sh --self-test

# 3. 非法参数:应退出 3
./healthcheck.sh --warn 95 --crit 90

# 4. 演示报告,肉眼核对文本格式
./healthcheck.sh --demo

# 5. JSON 必须能被标准解析器读取
./healthcheck.sh --json | jq .

第 3 步和第 5 步是硬门槛:参数校验没做,接了 cron 之后行为和预期不一致;JSON 转义没做,监控系统直接解析失败。

静态检查通过不等于能用

bash -n 加自测,不等于覆盖了所有发行版和生产环境。Ubuntu 和 Rocky 上 dfss 的行为细节有差异,systemd 版本也各不相同。正式使用前仍要在目标发行版测试机上验证一遍。

验证通过后再接入 cron 和监控系统,用退出码做告警分级。

复制全文 生成海报 Shell 运维 Linux

推荐文章

程序员茄子在线接单