以下是一个例子:
$ (newline=$'\n'; bash -c "trap 'trap ERR; echo handler' ERR; set -e;${newline}/bin/false")
如果我执行以下任何一项,处理程序就会执行:
- 删除换行符
- 在 EXIT 上陷入
- 在最后添加另一个命令
我怀疑 bash 有一个优化,如果只有一个命令,它就会调用 exec,而换行符后跟一个命令就会触发它。
我有间接证据:我在 strace 下运行;早期的 cmds 会先 vfork 然后 execve,但最后一个只调用 execv。
我在使用 GNU make 时遇到了这个问题,使用 .ONESHELL 和一个陷阱来打印退出代码和日志文件名,但如果最后一件事失败,陷阱就不会执行。
提前致谢。
答案1
我忘了这个问题。我为 bash 贡献了一个修复程序2016 年:
4/22
----
builtins/evalstring.c
- should_suppress_fork: don't suppress the fork if there are any traps
set, since that requires that we hang around to react to a signal or
collect the command's exit status and run something. Fixes bug
reported by Brian Vandenberg
正如我在问题中推测的那样,bash 确实进行了优化。我已经有一段时间没有看过代码了,但它或多或少做了以下事情:
- 解析直到找到完整的表达式,对其进行评估,然后解释或执行评估后剩下的内容
- 重复(1),直到只剩下一个表达式
- 如果最后一个表达式不需要 shell 的帮助并且可以传递给
exec()
系列函数,那么就这样做
我的解决办法是,通过检查是否有任何陷阱生效来添加“不需要 shell 的帮助”的定义。