对于使用 -c 传递的脚本,Bash 陷阱未在最后一个 cmd 上执行

对于使用 -c 传递的脚本,Bash 陷阱未在最后一个 cmd 上执行

以下是一个例子:

$ (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. 解析直到找到完整的表达式,对其进行评估,然后解释或执行评估后剩下的内容
  2. 重复(1),直到只剩下一个表达式
  3. 如果最后一个表达式不需要 shell 的帮助并且可以传递给exec()系列函数,那么就这样做

我的解决办法是,通过检查是否有任何陷阱生效来添加“不需要 shell 的帮助”的定义。

相关内容