シェルの-eについての研究
from 20250323
シェルの-eについての研究
The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !.
シェルで設定した-eオプションには、無視されるケースが存在する。
1. もし失敗するコマンドが以下の部分に該当する場合。
コマンドリストがwhile or untilキーワードのすぐ後の部分である
if文のtest部分である
最後の&& or ||に続くコマンドを除く&& or ||リストで実行される任意のコマンドの部分である
foo && barで、fooが失敗してもbarは実行される
パイプラインにおける最後以外の任意のコマンドである
2. コマンドの返り値が!で反転されている場合
未検証
code:bash
set -e
trap "echo ERR trap fired!" ERR
myfunc() {
false
}
if myfunc; then
echo "myfunc succeeded"
fi
echo "bar"
この場合、myfunc内のfalseは失敗するが、if myfuncの構文の中で実行されているため-eは無視される。
そのためシェルは即時終了せず、if文の終了ステータスに基づいて動作を続ける。
そして、if文がfalseだったため、echo "myfunc succeeded"は実行されないが、barは表示される。
一方、ifの中ではなく、直接myfuncを実行すると:
code:bash
set -e
trap "echo ERR trap fired!" ERR
myfunc() {
false
echo "This will not be printed"
}
myfunc # ここでエラーが発生すると -e によりシェルは即時終了
echo "bar"
# 注: echo "bar" は実行されない
この場合、falseの失敗で-eが有効なので、シェルは即時終了し、echo "bar"は実行されない
ただし、この場合trapは発火しない。
ERR trapの発動条件
シンプルなコマンド(単一のコマンド)が -e により失敗して即時終了すると、ERR トラップは発火しない。
複合コマンドの内部で失敗が発生し、それが -e による即時終了を引き起こす場合、ERR トラップが発火する。
code:bash
set -e
trap "echo ERR trap fired!" ERR
false # これが直接失敗すると ERR トラップは発火しない
code:bash
set -e
trap "echo ERR trap fired!" ERR
myfunc() {
false
}
myfunc # これが失敗すると ERR トラップが発火
If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits.
"while -e was being ignored"ってどういう意味?
When a subshell is entered, traps that are not being ignored are set to the default actions. This does not imply that the trap command cannot be used within the subshell to set new traps.
https://pubs.opengroup.org/onlinepubs/009695399/utilities/trap.html
trapはサブシェルに継承しない