在macos shell脚本中,捕获和处理命令失败需依赖 $? 获取退出码、set -e 自动终止、trap 清理资源及封装 run_or_die 等机制,形成“执行→检查→响应→清理”闭环。
在 macos 的 shell 脚本中,捕获和处理命令执行失败的关键是及时检查退出状态(exit code),并结合 set -e、trap 和条件判断等机制实现可控的错误响应。不是所有失败都会自动中断脚本,必须主动干预。
用 $? 获取上一条命令的退出码
每条命令执行后,Shell 会把它的退出状态保存在特殊变量 $? 中。值为 0 表示成功,非 0(通常是 1~255)表示失败。
ls /nonexistent if [ $? -ne 0 ]; then echo "目录不存在,跳过处理" exit 1 fi
注意:$? 只保留最近一次命令的结果,中间插入其他命令(哪怕是 echo)就会覆盖它。所以检查必须紧接在目标命令之后。
使用 set -e 让脚本在任意命令失败时立即退出
在脚本开头加上:
#!/bin/bash set -e
这样,只要任何一条命令返回非零退出码,脚本就终止执行。适合“全有或全无”的场景(如部署流程)。但要注意:
-
||和&&逻辑链中的失败不会触发set -e(因为它们本身是控制结构) -
if、while条件判断里的命令也不受set -e影响(这是设计行为)
用 trap 捕获异常并执行清理操作
trap 可以监听信号(如 ERR、EXIT、INT),在出错或退出前运行指定命令,确保资源释放:
macOS 微信消息自动化工具。通过 GUI 自动化实现:发送消息给指定联系人、读取聊天内容、监控新消息。适用于需要自动化微信操作的场景,如定时发送、批量回复、消息备份等。依赖 peekaboo 进行屏幕截图和 UI 交互。仅支持 macOS。开源地址:https://github.com/chairmanmia...
#!/bin/bash
tempfile=$(mktemp)
trap 'rm -f "$tempfile"; echo "已清理临时文件"; exit 1' ERR EXIT
# 模拟可能失败的操作
cp /etc/hosts "$tempfile" || { echo "读取 hosts 失败"; exit 1; }
grep "localhost" "$tempfile" > /dev/null
这里 ERR 在任意命令失败时触发,EXIT 保证无论成功失败都清理临时文件。
把错误处理封装成函数,提升复用性
例如定义一个安全执行函数,自动记录日志并可选退出:
run_or_die() {
local cmd="$1"
shift
if ! "$cmd" "$@"; then
echo "❌ 命令失败: $cmd $*" >&2
echo " 退出码: $?" >&2
exit 1
fi
}
# 使用示例
run_or_die cp /source/file /dest/
run_or_die chmod 644 /dest/file
这种写法让主逻辑更干净,也便于统一加日志、重试或告警。
注意 macOS 特有的陷阱
-
sudo后跟重定向(如sudo cmd > file)会失败——因为>是 shell 解析的,不经过 sudo 权限。应改用sudo sh -c 'cmd > file'或cmd | sudo tee file >/dev/null。 - 某些系统命令(如
defaults write)失败时不输出明显错误,但退出码非零,必须检查$?才能发现。 - SIP 保护路径(如
/System、/usr/bin)下命令即使加sudo也可能静默失败,此时$?可能是1,但 stderr 不一定有提示。
错误处理不是加个 if 就完事,而是围绕退出码建立反馈闭环:执行 → 检查 → 响应 → 清理。










