Bashがコマンド置換にerrexitオプションを渡さないのはなぜですか?

Bashがコマンド置換にerrexitオプションを渡さないのはなぜですか?

シェルオプションの設定set組み込みサブシェルから継承されます(少なくともerrexit)。これは次のように証明できます。

set -o errexit

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

echo "main:$BASHPID"
( foo )

しかし、これらのオプションは継承されないようです。コマンドの置き換え、Bash文書によると、これはサブシェルでもあります。証明する:

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

はい、これは予想される結果です。 bashは、POSIXモードでない場合(たとえば、実行されている場合sh)、errexitデフォルトで内部コマンド置換をリセットします。

errexitBash 4.4以降でコマンドの置き換えを維持するには、次のようにします。

inherit_errexit

errexit設定されている場合、コマンド置換はサブシェル環境で設定を解除するのではなく、このオプションの値を継承します。このオプションは、POSIXモードが有効な場合に有効になります。

(からバッシュマニュアル.)文書の他の部分より明確にするには:

inherit_errexitPOSIXモードを有効にすると、コマンドオーバーライドを実行するために作成されたサブシェルが親-eシェルから継承されるようにこのオプションを設定する効果があります。inherit_errexitBashは、アクティブでない-eサブシェルからこのオプションを消去します。

確認する:

$ 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

関連情報