為什麼 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 模式具有設定該選項的效果,因此產生的用於執行命令替換的子 shell 會從父 shellinherit_errexit繼承該選項的值。-e當該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

相關內容