Bash
POSIX

bash で 関数 || echo ng とかすると set -e が無効になる話

びっくりしたのでメモ。

bash スクリプトで set -e と関数と || を組み合わせると、関数内では set -e が無効になります。嘘のようですが本当です。

例えば以下のスクリプトは end f が出力されず start, start f, ng, end が出力されそうに見えます。

が、実際には ng が出力されず end f が出力されます。

set -e

f() {
echo "start f"
false
echo
"end f"
}

echo "start"
f || echo "ng"
echo "end"

結果:

start

start f
end f
end

なかなかに不可解です。


どうすればよいのか

f を関数ではなく別コマンドとするか、set -e に頼らず真面目にエラー処理をするのがよいと思います。


それらしい回答

https://ja.stackoverflow.com/questions/27866/関数と-e-オプションを併用すると意図通りに動作しないのはなぜ


質問の例ですとfalseは関数中では単独で呼び出されていますが、その関数を呼び出しているのは&&を含んだコマンド列ですので、


&& または || によるコマンドのリストの一部


という事になるのだと思います。


https://lists.gnu.org/archive/html/bug-bash/2012-12/msg00094.html


Indeed, the correct behavior mandated by POSIX (namely, that 'set -e' is completely ignored for the duration of the entire body of f(), because f was invoked in a context that ignores 'set -e') is not intuitive. But it is standardized, so we have to live with it.


僕らはPOSIXと共に生きなければいけないのです。不可解でも納得しましょう。