Shell脚本适用于单机、轻量、即时响应、依赖少的运维场景;多机、并发、回滚等复杂需求应选Python或Ansible;需注意环境变量、绝对路径、锁机制及命令可靠性。

Shell 脚本不是万能胶,但大多数 Linux 运维自动化场景里,它确实是最快能跑起来、最不容易翻车的那一个工具。
什么时候该用 bash 而不是 Python 或 Ansible
判断标准很简单:任务是否满足「单机、轻量、即时响应、依赖少」这四个条件。比如日志轮转、服务健康检查、临时备份、磁盘空间告警——这些用 bash 写几行就完事,加个 cron 就能跑;换成 Python 得装解释器环境,Ansible 还要配 inventory 和 playbook 目录结构,小题大做。
- 运维主机上默认就有
/bin/bash,不用额外安装 -
ps、df、curl、systemctl这些命令原生可调,不需封装库 - 调试时直接
bash -x script.sh就能看到每步执行逻辑,比查 Python traceback 快得多 - 注意:一旦涉及多机并发、状态收敛、回滚机制或复杂配置渲染,
bash就该让位了——它没原生错误传播链,set -e也拦不住管道中的失败
if 判断里别直接写 grep,要用 [[ ]] 或 test
常见错误是这样写:
if grep "running" <(systemctl is-active nginx); then ...
看着能跑,但实际不可靠:如果 systemctl is-active 报错(比如服务不存在),grep 可能仍返回 0,导致误判。更稳的方式是先捕获状态,再用 [[ ]] 判断:
status=$(systemctl is-active nginx 2>/dev/null) if [[ "$status" == "active" ]]; then echo "nginx is up" fi
-
[[ ]]是 bash 内建,比外部test快,且支持模式匹配和空值安全 - 永远对命令替换结果加双引号:
"$status",避免空格或换行导致语法错误 - 别信
grep -q的退出码——它只反映是否匹配到内容,不反映上游命令是否成功
cron 执行脚本失败?先看环境变量和路径
cron 默认只加载极简环境:PATH=/usr/bin:/bin,没有 ~/.bashrc,也没有你手动设置的别名或函数。所以脚本里写 python3 /path/to/script.py 很可能报 command not found,因为 python3 不在默认 PATH 里。
- 在脚本开头显式声明环境:
#!/bin/bash后加PATH="/usr/local/bin:/usr/bin:/bin" - 所有命令尽量用绝对路径:
/usr/bin/systemctl、/bin/date,避免歧义 - 调试时加日志重定向:
* * * * * /path/to/backup.sh >> /var/log/backup.log 2>&1,否则失败无声无息 - 注意
cron的时间是系统本地时区,不是你的终端时区——date输出和cron解析可能不一致
日志清理类脚本必须加锁,否则可能删错文件
多个 cron 实例或手动触发同时运行,find /var/log -name "*.log" -mtime +30 -delete 这种命令极易引发竞态:A 进程刚查完列表,B 进程删了一半,A 接着删就可能误删刚生成的新日志。
- 用
flock最省事:flock -n /tmp/cleanup.lock -c "find ... -delete",加-n非阻塞,失败直接退出 - 不要自己用
touch+rm模拟锁——stat和unlink之间有时间窗口 - 删除前加
-print看清楚要删什么,上线前先跑一遍 dry-run - 更稳妥的做法是把清理逻辑封装进函数,配合
trap确保异常时也能释放锁
Shell 自动化真正的难点从来不在语法,而在于对「环境不确定性」的预判——路径、权限、时区、并发、命令兼容性,每一处都可能让脚本在某台机器上安静地失效。










