Ubuntu 12.04.2を使用しています。 「trap」コマンドを使用してシェルスクリプトの異常またはエラーをキャプチャしようとしていますが、「Error」出口を手動でトリガーしようとしています。
出口1を試しましたが、「エラー」信号をトリガーしません。
#!/bin/bash
func()
{
exit 1
}
trap "echo hi" INT TERM ERR
func
「エラー」終了信号を手動でトリガーする方法がわからない場合は、
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で正常に終了すると、 waitおよびcooperative exit 端末割り込みの処理。そのため、実際に中断されたことを親に報告し、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ハンドラーを終了しない、戻り値を削除してfuncの最後のステートメントとしてfalse
を配置するなど、さまざまな変更を試すことができます。