优先选bash,因其轻量、无依赖、启动快,适合纯系统指标采集;python仅在需日志解析、api调用或生成html报告时使用。

巡检脚本该用 bash 还是 Python?
优先选 bash,除非你要做日志解析、API 调用或生成 HTML 报告。纯系统指标采集(CPU、内存、磁盘、进程、服务状态)用 bash 更轻量、无依赖、启动快。Python 虽然写起来顺手,但每次执行都要加载解释器,在低配服务器上可能拖慢巡检节奏,而且容易因环境缺失 psutil 或 requests 直接失败。
常见错误现象:/usr/bin/env: ‘python’: No such file or Directory —— 很多 centos 7+ 默认没装 python3,连软链接都未必有;而 bash 在所有 linux 发行版里都是稳的。
- 简单指标采集(
df -h、free -m、systemctl is-active sshd)全用bash写,50 行内搞定 - 需要正则提取日志关键字(比如从
/var/log/secure找 failed login)再用grep -E+awk,别急着上 Python - 真要调用外部 API(如钉钉机器人推送),用
curl拼 json 就够了,不用引入requests
怎么让脚本安全地获取 root 权限又不暴露密码?
别在脚本里写 sudo su -c 或硬编码密码。直接用 sudo 配置免密命令白名单最稳妥。运维账号本身不该有 root 密码,也不该用 ssh root@localhost 绕。
使用场景:脚本需执行 df -h(普通用户可运行)和 journalctl -n 20 --since "1 hour ago"(默认非 root 不可见)—— 后者必须提权。
- 编辑
/etc/sudoers.d/healthcheck(用visudo),加一行:monitor ALL=(root) NOPASSWD: /usr/bin/journalctl - 脚本里调用时写成
sudo journalctl -n 20 --since "1 hour ago" | grep -i 'failed|denied',不加-S或交互式输密码 - 禁止写
ALL=(root) NOPASSWD: ALL,这是高危配置;只放开真正需要的二进制路径,且带参数限制(必要时用sha256sum校验命令完整性)
输出结果怎么存才方便后续分析?
别用纯文本追加到 /tmp/health.log。时间戳混乱、无结构、难 grep。直接输出为带字段的 TS SV(Tab-Separated Values),文件名带日期,保留最近 7 天即可。
性能影响:每天写一次大文件比每分钟追加小段快得多;用 date +%Y%m%d 命名,避免 find /var/log/health -mtime +7 -delete 误删。
- 每行格式统一:
$(date '+%Y-%m-%d %H:%M') $(hostname) $(df -h / | awk 'NR==2 {print $5}') $(systemctl is-active nginx) - 输出重定向用
> /var/log/health/$(date +%Y%m%d).tsv,不是>>,避免跨天混写 - 检查磁盘空间前先
df /var/log | awk '$5 > 90 {exit 1}',超阈值就跳过写入,防止巡检本身把磁盘打满
定时执行时为什么 cron 日志总为空?
cron 环境变量和你手动执行时完全不同:PATH 极简、没 ~/.bashrc、$HOME 可能指向 /root。脚本里写的 python3 或 jq,cron 找不到。
错误现象:CRON[1234]: (root) CMD (/opt/scripts/check.sh) 出现在 /var/log/cron,但脚本没输出、没发通知、也没报错文件。
- 脚本开头固定写三行:
#!/bin/bash、export PATH="/usr/local/bin:/usr/bin:/bin"、cd /opt/scripts || exit 1 - 所有命令用绝对路径:
/bin/df、/usr/bin/systemctl、/usr/bin/journalctl,别信$PATH - 重定向 stderr 到日志:
/opt/scripts/check.sh >> /var/log/health/cron.log 2>&1,否则错误全丢进黑洞
最容易被忽略的是环境隔离——哪怕脚本本地测试全通,放进 cron 就静默失败。每次改完先手动跑 env -i /bin/bash -c '/opt/scripts/check.sh' 模拟 cron 环境,再扔进定时任务。