5.2.7 退出码与错误处理基础
退出码与错误处理基础#
退出码(Exit Status)用于表示命令执行结果,0 成功,非 0 失败。脚本通过 $? 获取上一条命令的退出状态。正确使用退出码能让自动化流程可预测、可恢复。
原理草图:命令链路与退出码流转#
1) 获取与返回退出码(含命令解释)#
# 获取上一条命令退出码:$? 只记录“上一条”命令的状态
ls /tmp
echo $? # 0 表示 ls 成功
# 自定义脚本退出码:exit N
if [[ ! -f /etc/passwd ]]; then
echo "file not found" >&2 # 输出到 stderr
exit 2 # 自定义错误码
fi
exit 0
命令解释:$? 读取上一条命令的退出码;exit N 终止脚本并返回 N。
2) 常见退出码约定(运维常见)#
0:成功1:一般性错误(权限不足/语法错误)2:参数使用不当126:命令不可执行127:命令未找到128+n:被信号终止(如130=Ctrl+C)
3) 基本错误处理模式(完整可执行示例)#
#!/bin/bash
# /opt/scripts/backup.sh
set -euo pipefail
SRC="/data/a"
DST="/backup/a"
# 依赖检查
if ! command -v rsync >/dev/null 2>&1; then
echo "error: rsync not found" >&2
exit 127
fi
# 关键操作 + 立即判断
rsync -a "$SRC" "$DST" || { echo "error: rsync failed" >&2; exit 1; }
echo "backup ok"
exit 0
命令解释:
- set -euo pipefail:遇错退出/未定义变量报错/管道任一失败即失败
- command -v rsync:检查命令是否存在
- rsync -a:归档模式(保持权限/时间)
预期效果:依赖存在且同步成功则输出 backup ok,失败则脚本以非 0 退出。
4) 标准错误输出与日志分离#
# 正常输出到 stdout,错误输出到 stderr
echo "task ok"
echo "error: invalid input" >&2
# 将错误日志单独收集
/opt/scripts/backup.sh 1>/var/log/backup.out 2>/var/log/backup.err
命令解释:1> 重定向标准输出,2> 重定向标准错误。
5) 与信号相关的退出码(练习用)#
# 运行并手动 Ctrl+C 终止,观察退出码
sleep 100
echo $?
预期效果:按 Ctrl+C 后退出码为 130。
6) 小型场景:服务重启失败即退出#
#!/bin/bash
# /opt/scripts/restart_nginx.sh
set -euo pipefail
if systemctl restart nginx; then
echo "nginx restarted"
else
echo "restart failed" >&2
exit 1
fi
命令解释:systemctl restart 成功返回 0,失败返回非 0。
7) 排错清单(退出码相关)#
- 127:命令未找到
- 排查:
command -v <cmd>、检查PATH - 126:命令不可执行
- 排查:
ls -l <cmd>、chmod +x <cmd> - 1/2:参数或权限问题
- 排查:
<cmd> --help、id、ls -l - 管道失败未捕获
- 排查:是否启用
set -o pipefail
8) 练习(动手操作)#
- 练习1:自定义退出码
写脚本判断/etc/hosts是否存在,存在则exit 0,不存在exit 3,并输出到stderr。 - 练习2:依赖检查
写脚本检查curl和jq是否存在,缺任一退出127。 - 练习3:管道错误捕获
对比set -o pipefail前后:
bash grep "root" /not_exists | wc -l echo $?