回答:
ERR
トラップは、シェル自体が非ゼロのエラーコードで終了したときにコードを実行し、それだけにはされていない場合に任意のコマンドの一部ではないことをシェルによって実行条件(のようにif cmd...
、またはcmd || ...
非ゼロの...)終了終了ステータス(set -e
シェルを終了する原因と同じ条件)。
ゼロ以外の終了ステータスでシェルの終了時にコードを実行する場合は、EXIT
代わりにトラップを追加して確認する必要$?
があります。
trap '[ "$?" -eq 0 ] || echo hi' EXIT
ただし、トラップされたシグナルでは、シグナルトラップとEXITトラップの両方が実行されるため、次のようにすることができます。
unset killed_by
trap 'killed_by=INT;exit' INT
trap 'killed_by=TERM;exit' TERM
trap '
ret=$?
if [ -n "$killed_by" ]; then
echo >&2 "Ouch! Killed by $killed_by"
exit 1
elif [ "$ret" -ne 0 ]; then
echo >&2 "Died with error code $ret"
fi' EXIT
または$((signum + 128))
、シグナルのような終了ステータスを使用するには:
for sig in INT TERM HUP; do
trap "exit $((128 + $(kill -l "$sig")))" "$sig"
done
trap '
ret=$?
[ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"' EXIT
ただし、親プロセスが、端末割り込みの待機および協調終了処理bash
を実装するシェルのような場合、SIGINTまたはSIGQUITで正常に終了すると、迷惑な副作用が生じる可能性があることに注意してください。そのため、実際に中断されたことを親に報告し、SIGINT / SIGQUITを受信した場合は自分自身を終了することも考慮するように、代わりに同じ信号で自分自身を殺すようにしてください。
unset killed_by
for sig in INT QUIT TERM HUP; do
trap "exit $((128 + $(kill -l "$sig"))); killed_by=$sig" "$sig"
done
trap '
ret=$?
[ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"
if [ -n "$killed_by" ]; then
trap - "$killed_by" # reset handler
# ulimit -c 0 # possibly disable core dumps
kill -s "$killed_by" "$$"
else
exec "$ret"
fi' EXIT
ERR
トラップを起動する場合は、false
またはなどのゼロ以外の終了ステータスでコマンドを実行し test
ます。
関数の終了時にステータスを設定するには、exitではなくreturnを使用します(関数がreturnなしでフォールスルーする場合、ステータスは最後に実行されたステートメントのステータスになります。)質問の例の代わりにreturn
使用exit
すると、私はあなたが意図したと思う:トラップはERR疑似信号でトリガーされ、「hi」が出力されます。その他の考慮事項については、これを試してください:
#!/bin/bash
func()
{
echo 'in func'
return 99
echo 'still in func'
}
trap 'echo "done"' EXIT
trap 'status=$?; echo "error status is $status"; trap - EXIT; exit $status' ERR
func
echo 'returned from func'
0を返す、ERRトラップをコメントアウトする、ERRハンドラー内でEXITトラップをキャンセルしない、ERRハンドラーを終了しない、リターンを削除false
してfuncの最後のステートメントとして置くなど、さまざまな変更を試すことができます。