web-dev-qa-db-ja.com

トラップERRの動作がbashバージョン3および4と異なるのはなぜですか?

バックグラウンド

次のコードをbash3、4、5でそれぞれ実行すると、異なる結果が得られます。

(function handle_error () { echo ERROR; }; trap handle_error ERR; (exit 1))

(exit 1)が、失敗する可能性のある呼び出すコマンドであると想像してください。この場合、それは常に失敗しますが、それは実際には問題ではありません。ゼロ以外の終了コードで終了するときにhandle_errorが呼び出されるようにします。マニュアルによると、これはまさにtrap handle_error ERRがすべきことです。

問題

Bash 3のバージョンのローカルシステムと、bash4のバージョンのまったく異なるオペレーティングシステムのリモートシステムがあります。

  • bash 3.2.57(1)、3.2.48(1):出力を返しません。 trapビルトインのman bashからの抜粋:

    SigspecがERRの場合、次の条件に従って、単純なコマンドの終了ステータスがゼロ以外の場合は常にコマンドargが実行されます。

  • bash 4.4.23(1)、4.4.12(1):期待どおりにERRORを出力します。 trapビルトインのman bashからの抜粋:

    SigspecがERRの場合、次の条件に従って、パイプライン(単一の単純なコマンドで構成されている場合があります)、リスト、または複合コマンドがゼロ以外の終了ステータスを返すたびに、コマンドargが実行されます。

  • bash 5.0.2(1):期待どおりにERRORを出力します。

ドキュメントから、動作は両方のバージョンで同じである必要があると思いますが、そうではありません。

Freenodeで#bashにログオンし、シェルボット(ニックshbot)を使用して、この動作がすべてのメジャーバージョン3、4、5で同じように異なることも確認しました。メジャーバージョンを指定します。このシェルボットは、私が試した両方のシステムとは異なるオペレーティングシステムで実行され、アクセスできる同じメジャーバージョンのbashとは異なるマイナーバージョンが使用されています。

質問

この動作がbashのバージョン3、4、および5と異なる理由を説明する信頼できる情報源を誰かが指摘できますか?これがバグだとは信じがたいです。私が見逃している別の理由があるに違いありません。

2
justinpc

これはBash3.2のバグのようです。

changelog に、それに直接一致するエントリが見つかりません。 POSIXコンセンサスに一致するようにerrexitオプションの動作を変更することについては漠然とした言及しかありません(bash-4.0-rc1からbash-4.0-releaseへの変更の項目l)。

errexitにも同様の問題があるため、これはBash 3.2ではトリガーされませんが、Bash 4.0ではトリガーされます(サブシェルコマンドが失敗するとシェルが終了するため、何も出力されないはずです)。 :

$ ./bash3.2 -c 'set -e; (exit 1); echo end.'
end.

これは両方のバージョンで機能するため、ここでの問題はサブシェルのように見えることに注意してください。

$ ./bash3.2 -c 'trap "echo ERROR" ERR; false'
ERROR
2
ilkkachu