为什么 Bash 不将 errexit 选项传递给命令替换?

为什么 Bash 不将 errexit 选项传递给命令替换?

外壳选项设置set内置在子 shell 中继承(至少是errexit)。这可以通过以下方式证明:

set -o errexit

function foo() {
    echo "foo:$BASHPID"
    false
    echo 'after' 
}

echo "main:$BASHPID"
( foo )

然而,这些选项似乎没有继承命令替换,根据 Bash 文档,它也应该是子 shell。证明:

set -o errexit

function foo() {
    echo "foo:$BASHPID"
    false
    echo 'after' 
}

echo "main:$BASHPID"
output=$(foo)
echo "output: $output"

预期输出:

main:123
output: foo:124

实际输出:

main:123
output: foo:124
after

这是预期的还是错误?

答案1

是的,这是预期的,当不处于 POSIX 模式时(例如运行 as 时sh),basherrexit默认情况下会重置内部命令替换。

如果您想errexit在 bash 4.4 或更高版本中保留命令替换,请使用:

inherit_errexit

如果设置,命令替换将继承该选项的值errexit,而不是在子 shell 环境中取消设置。该选项在 POSIX 模式启用时启用。

(从bash手册.)文档的另一部分使其更明确:

启用 POSIX 模式具有设置该选项的效果inherit_errexit,因此生成的用于执行命令替换的子 shell 继承了-e,因此生成的用于执行命令替换的子 shell 会从父 shell当该inherit_errexit选项未启用时,Bash 会清除-e此类子 shell 中的该选项。

核实:

$ bash -o errexit -c 'echo "$(echo "$SHELLOPTS")"'
braceexpand:hashall:interactive-comments
$ bash -o errexit -O inherit_errexit -c 'echo "$(echo "$SHELLOPTS")"'
braceexpand:errexit:hashall:interactive-comments

在 bash 4.2 及更早版本中,errexit显示在前者中,但仍然有效禁用:

$ bash-4.2 -o errexit c 'echo "$(false; echo "$SHELLOPTS")"'
braceexpand:errexit:hashall:interactive-comments
$ bash-4.2 -o posix -o errexit -c 'echo "<$(false; echo "$SHELLOPTS")> $?"'
<> 1

相关内容