次のコードを使用してINTとERRをキャプチャします。
set -ex -o pipefail
dest=$(mktemp -d)
cd "$dest"
trap "echo; echo Clean up; rm -rf $dest" INT ERR
sleep 9999
クリーンコールバックを押すと^C
複数回実行されます。
++ echo Clean up
Clean up
++ rm -rf /tmp/tmp.KYXL110516
++ echo
++ echo Clean up
Clean up
++ rm -rf /tmp/tmp.KYXL110516
これが予想される動作ですか?一度だけできますか?
答え1
INT信号とERR信号の両方を受信します。 SIGINT はsleep
ゼロ以外の戻りコードで終了します。ゼロ以外の戻りコードは、SIGERR トラップをトリガーします。
sigspecがERRの場合、パイプライン(単一の単純なコマンドで構成できます)、リスト、または複合コマンドがゼロ以外の終了状態を返すたびに、arg ...コマンドが実行されます。
個々のトラップを調べる例:
set -ex -o pipefail
trap "echo Clean up for INT" INT
trap "echo Clean up for ERR" ERR
sleep 9999
実行してCtrl-Cを押します。
+ trap 'echo Clean up for INT' INT
+ trap 'echo Clean up for ERR' ERR
+ sleep 9999
^C++ echo Clean up for INT
Clean up for INT
++ echo Clean up for ERR
Clean up for ERR
トラップを一度だけ呼び出す場合、1つのオプションはトラップERR
内でトラップをリセットすることです。INT
...
trap "echo Clean up for INT; trap ERR" INT ERR
...
...結果は次のとおりです。
+ trap 'echo Clean up for INT; trap ERR' INT ERR
+ sleep 9999
^C++ echo Clean up for INT
Clean up for INT
++ trap ERR
答え2
ではbash
簡単に置き換えることができますtrap "my-cleanup-command" EXIT
。このトラップは、SIGINTの送信時など、スクリプトの終了時に実行されます。私の考えでは、これは通常よりエレガントなアプローチです...
bashに固有の事実を除いて。 EXIT トラップは POSIX で言及されていますが、その動作は指定されていません。他の多くのシェルでは、シグナルによってシェルがシャットダウンした場合、EXITトラップは実行されません。
https://unix.stackexchange.com/a/57960/29483
私は時々シェルスクリプトが本当に嫌いです:).
リンクされた回答を見ると、最初のトラップ後にコードが実行されないようにする低 bash 関連の方法は、すぐに終了することです。これには他の方法を使用することもできますが、これが私が試してみる最も簡単な方法です。
cleanup() {
echo "Clean up"
rm -rf "$dest"
}
trap cleanup EXIT
trap "exit 1" INT ERR