🐛 一次 Bash 脚本调试经历:set -e
与 bru run 返回码的问题
在一次日常的脚本自动化中,我遇到了一个看似简单但实则隐藏坑点的问题。最终的 root cause 出乎意料,记录下来希望对你也有帮助。
🧩 背景
我们在使用 bash
脚本执行一系列任务,过程中使用了一个内部工具命令 bru run
来执行测试任务。脚本结构大致如下:
#!/bin/bash
set -e
bru run some-task
if [ $? -eq 0 ]; then
echo "Run succeeded."
else
echo "Run failed."
exit 1
fi
脚本逻辑是:
- 启用
set -e
来确保脚本在遇到任何非 0 返回码时立即退出 - 执行
bru run
- 根据返回码判断是否继续处理
结果:脚本总是在 bru run
后直接退出,后续逻辑根本不会执行。
❗问题分析
我们观察到:
bru run
实际返回值为 1,这在它的语义下是一个正常情况,比如任务执行中有失败但仍生成报告;- 由于
set -e
的开启,bash
在遇到bru run
返回非 0 的时候就立刻退出脚本,根本没有机会进入后续的 if 判断; - 此外,即使关闭
set -e
,下面这种判断也值得反思:
if [ $? -eq 0 ]; then
因为如果你允许某些非 0 返回作为“正常情况”,就需要更细粒度的控制错误处理逻辑。
✅ 正确做法
目标:
- 即使
bru run
返回 1,脚本也要能继续往下执行; - 但仍然对非预期错误保持敏感;
- 避免
set -e
误伤“合法失败”。
方法一:局部关闭 set -e
,手动处理错误
#!/bin/bash
set -e
set +e
bru run some-task
result=$?
set -e
if [ $result -eq 0 ] || [ $result -eq 1 ]; then
echo "bru run finished with code $result (acceptable)"
else
echo "bru run failed with unexpected code $result"
exit 1
fi
echo "Continue processing..."
这样你可以:
- 保留
set -e
的大部分保护作用; - 对
bru run
的特殊行为做例外处理。
方法二:完全不使用 set -e
,显式判断关键命令结果
如果你脚本中类似的命令很多,不如完全不依赖 set -e
,自己控制每一步:
#!/bin/bash
bru run some-task
result=$?
if [ $result -ne 0 ] && [ $result -ne 1 ]; then
echo "Unexpected error code: $result"
exit 1
fi
echo "Report generated, continuing..."
🎯 结语
这次问题让我意识到:
- 并不是所有非 0 返回码都意味着“错误”,上下文语义很重要;
set -e
是一把双刃剑,虽然能简化错误处理,但遇到特殊返回值时容易踩坑;- 写脚本时要清楚每个命令的“返回语义”,才能避免误判。
希望这个经验能帮你在自动化任务中少踩坑!
💬 如果你也遇到过类似的情况,欢迎留言交流!