これは、現在のディレクトリに一時ディレクトリを設定し、終了時にそれを削除するトラップを設定する簡単なスクリプトです。
#filename: script
set -x
trap 'rm -rf "$d"' exit
d=`TMPDIR=$PWD mktemp -d`
"$@"
ksh script sleep 100
またはを実行しbash script sleep 100
、 で中断するとC-C
、トラップが実行され、ディレクトリが削除されます。 では機能しませんdash
。なぜでしょうか? これはバグですか、それとも意図された動作ですか?
答え1
zsh
、pdksh
(ただし、 の最近のバージョンはmksh
そこから派生したものではありません)yash
、 Bourne シェルは のように動作しますdash
。
bash
、、ksh88
およびのみksh93
がmksh
それ以外の動作をします。
SIGINT
POSIX 仕様では正しい動作が何であるかは明確ではありませんが、シェルがシグナル(またはその他のシグナル)のデフォルト ハンドラーをオーバーライドできるという記述はありません。
EXIT
トラップ アクションは が呼び出されたときに評価される必要があると書かれていますが、私の知る限り、たとえば、または構文エラーや特殊な組み込みの失敗などのエラー条件exit
の結果としてシェルが終了したときに評価される必要があるかどうかさえ書かれていません。set -e
set -u
シグナルの受信時にトラップを実行できるようにするにはEXIT
、シェルがそのシグナルにハンドラーをインストールする必要があります。
これがksh
、、およびmksh
の機能ですが、これらが処理するシグナルのリストは、bash
3 つの実装間で異なります。3 つすべてに共通するシグナルはINT
、、、、およびのみのようです。QUIT
TERM
ALRM
HUP
トラップを何らかのシグナルで実行したい場合EXIT
、移植性の高い方法はそれらのシグナルを自分で処理することです。
trap 'exit 1' INT HUP QUIT TERM ALRM USR1
trap 'cleanup' EXIT
ただし、このアプローチは では機能しません。 は、トラップ ハンドラーから が呼び出された場合、トラップzsh
を実行しません。EXIT
exit
また、信号による死亡を親に報告することもできません。
代わりに、次のようにすることもできます。
for sig in INT QUIT HUP TERM ALRM USR1; do
trap "
cleanup
trap - $sig EXIT
kill -s $sig "'"$$"' "$sig"
done
trap cleanup EXIT
cleanup
ただし、 の実行中にさらにシグナルが到着すると、が再度実行される可能性があることに注意してください。が複数回呼び出された場合に が正しく動作することを確認したり、実行中にシグナルを無視したりすることcleanup
をお勧めします。cleanup
答え2
警告:exit
動作は保証されません。代わりにEXIT
POSIX標準では、EXIT
シグナルの場合にもトラップを実行するかどうかは定義されておらず、Bourne ShellがEXIT
あなたが言及したケースではトラップを呼び出さないという事実を考えると、あなたが入力しているのは明らかです。未指定行動。