【问题标题】:Parent trap visible but not run by subshell父陷阱可见但不由子外壳运行
【发布时间】:2019-03-23 01:49:35
【问题描述】:

针对 Bash 5.0.2 测试

根据GNU Bash Reference Manual

Bash 通过在子shell 环境中执行[the] 命令来执行[命令替换] 的扩展

根据The Open Group Base Specifications Issue 6

当进入一个子shell时,未被忽略的陷阱被设置为默认动作。


所以在运行以下脚本时:

function a {
   trap -p EXIT
}

trap "echo 'parent'" EXIT

echo "$(a)"
(a)

trap - EXIT

echo 'exiting'

...我希望输出:

exiting

...但我得到了:

trap -- 'echo '\''parent'\''' EXIT
trap -- 'echo '\''parent'\''' EXIT
exiting

... 意味着函数 a - 即使它在子 shell 中运行 - 正在查看父 shell 的陷阱命令(通过 trap -p)但不执行它们。


这是怎么回事?

【问题讨论】:

  • 您似乎使用的是 bash 3.2;如果有的话,bash 的更高版本会朝相反的方向移动,对echo "$(a)" (a) 执行陷阱。 (在当前版本 5.0.3 中仍然如此。)
  • 我针对 Bash 3.2.57 和 Bash 5.0.2 进行了测试。对我来说结果相同。
  • 嗯,我在 3.2.37 中没有看到 (a) 的继承陷阱。

标签: bash subshell command-substitution bash-trap


【解决方案1】:

您会注意到陷阱完全按照规范触发。只是trap 的输出出乎意料。

这是 Bash 4.2 (release notes) 中的一项功能:

b.  Subshells begun to execute command substitutions or run shell functions or
    builtins in subshells do not reset trap strings until a new trap is
    specified.  This allows $(trap) to display the caller's traps and the
    trap strings to persist until a new trap is set.

通常,人们会认为这是理所当然的。考虑一下这个完全不足为奇的 Bash 交换:

bash$ trap
trap -- 'foo' EXIT
trap -- 'bar' SIGINT

bash$ trap | grep EXIT
trap -- 'foo' EXIT

现在看看在 Dash、Ksh 或 Zsh 等其他 shell 中的结果:

dash$ trap
trap -- 'foo' EXIT
trap -- 'bar' INT

dash$ trap | grep EXIT
(no output)

这也许更正确,但我怀疑很多人会期待它。

【讨论】:

  • 是的,这是这个答案中引用的部分
【解决方案2】:

您似乎正在阅读旧版本的规范。在most recent one

当进入子shell时,不被忽略的陷阱应设置为默认操作,除非在命令替换仅包含单个陷阱命令的情况下,此时陷阱不需要更改。

【讨论】:

  • 实际上,我不确定这一点。它表示命令替换的一些异常,但规范中的示例与当前情况并不真正匹配,也没有解释为什么(a)也继承了陷阱。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多