外壳选项设置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 模式启用时启用。
启用 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