父陷阱可见,但不能通过子shell运行

时间:2019-03-22 14:09:27

标签: bash subshell command-substitution trap

经过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-尽管它正在子外壳中运行-却看到父外壳的trap命令(通过trap -p)却没有执行。


这是怎么回事?

2 个答案:

答案 0 :(得分:2)

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

  

进入子shell时,除非命令替换仅包含一个陷阱命令,否则不需要更改陷阱,除非是仅包含单个陷阱命令的命令替换,否则应将不被忽略的陷阱设置为默认操作。

答案 1 :(得分: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)

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