set -e 会让脚本在任何命令返回非零退出状态时立即终止执行;它仅对简单命令生效,例外包括 &&/|| 后的命令、if/while 中的测试命令、! 取反命令等。

set -e 是 Bash 中最常用也最容易被误解的错误处理机制之一。它会让脚本在**任何命令返回非零退出状态时立即终止执行**,而不是继续往下跑——这能避免后续命令在错误前提下运行,造成更隐蔽的问题。
什么时候 set -e 会真正生效
它只对“简单命令”起作用,比如普通命令、管道中的最后一个命令、命令替换里的命令等。但以下情况不会触发退出:
- 命令后跟 && 或 ||:例如
grep "foo" file || echo "not found",即使 grep 失败也不退出 - if、while、until 条件判断中的测试命令:如
if false; then ...; fi不会因 false 退出 - 命令以 !(取反) 开头:如
! ls /missing,失败反而变成成功,不触发 -e - 命令在 for/while 循环体中单独执行,且未被逻辑操作符包裹时,仍受 -e 影响
怎么正确启用和使用
推荐在脚本开头就开启,并配合 set -u(检测未定义变量)和 set -o pipefail(让管道中任一命令失败都报错),形成基础防护组合:
#!/bin/bash set -euo pipefail
如果某条命令预期可能失败且你希望忽略它,有几种安全写法:
- 用
|| true明确表示“失败也没关系”:rm -f /tmp/stale.lock || true - 用 if 封装并显式处理:
if ! command_that_might_fail; then echo "warn: skipped"; fi - 临时关闭再恢复:
set +e; dangerous_command; set -e(慎用,易遗漏恢复)
常见陷阱和调试技巧
开启 -e 后脚本突然提前退出?先检查是否踩了上面提到的“例外场景”。调试时可加 set -x 查看实际执行流:
set -euxo pipefail
这样每条命令执行前都会打印出来,方便定位哪一行“悄悄失败”了却没被注意到。另外注意:函数内部也受全局 set -e 控制,无需重复设置。
替代方案:更精细的错误处理
如果 -e 的“一刀切”太粗暴(比如需要区分不同错误码做不同处理),可以改用显式检查:
- 用
$?检查上一条命令退出码:some_cmd; if [ $? -ne 0 ]; then handle_error; fi - 把关键步骤封装成函数,统一返回值约定和日志输出
- 结合 trap 在退出前清理资源:
trap 'rm -f /tmp/tempfile' EXIT
set -e 不是银弹,但它确实是提升脚本健壮性的低成本起点。用好它,比靠人工反复加 if 判断更简洁可靠。











