kshとbashのダッシュ対終了トラップ

kshとbashのダッシュ対終了トラップ

これは、現在のディレクトリに一時ディレクトリを設定し、終了時に削除するようにトラップを設定する簡単なスクリプトです。

#filename: script   
set -x  
trap 'rm -rf "$d"' exit
d=`TMPDIR=$PWD mktemp -d`
"$@"

ksh script sleep 100orを実行しbash script sleep 100て中断すると、C-Cトラップが実行され、ディレクトリが削除されます。動作しませんdash。なぜですか?これはバグですか、それとも意図的な動作ですか?

答え1

zsh、(pdksh最新バージョンではありませんが)Bourneシェルは。mkshyashdash

bashksh88その他の操作のみ可能ですksh93mksh

SIGINTPOSIX仕様では正しい動作が何であるかは不明ですが、シェルがシグナルのデフォルトハンドラをオーバーライドすることを許可するものはありません。

EXITトラップ操作は呼び出されたときに評価する必要があると言いますが、私が知っている限り、たとえば構文エラーや特殊な組み込みなどのエラー条件のためにシェルが終了したexitときに評価する必要はありません。機能障害時)。set -eset -u

シグナルを受信した後にトラップを実行できるようにするには、シェルがシグナルEXITにハンドラーをインストールする必要があります。

それがまさにkshmkshそしてすることですが、bash彼らが処理する信号のリストは3つの実装間で異なります。 3 つの実装間の唯一の共通信号はINT、 と ですQUITTERMALRMHUP

EXIT特定の信号に対してトラップを実行する場合、移植可能なアプローチはその信号を直接処理することです。

trap 'exit 1' INT HUP QUIT TERM ALRM USR1
trap 'cleanup' EXIT

ただし、このアプローチは機能せず、トラップハンドラから呼び出されてもzshトラップは実行されませんEXITexit

また、両親に死亡報告をすることもできません。

したがって、次のことができます。

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でトラップを呼び出さないことを考慮すると、次のように入力することは明らかです。指定されていないアクション。

関連情報