web-dev-qa-db-ja.com

EXIT以外のトラップを指定する必要がありますか?

私は多くのシェルスクリプトを見ます:

 trap cmd 0 1 2 3 13 15#EXIT HUP INT QUIT PIPE TERM 

現在アクセスしているすべてのシェルで、0以外のすべてのトラップは冗長であり、トラップが単純に指定されている場合は、シグナルの受信時にcmdが実行されます。

 trap cmd 0 

後者の仕様で十分ですか、または一部のシェルでは他の信号を指定する必要がありますか?

34
William Pursell

すべての場合において、トラップ0はスクリプトの終了直前に実行されるので、クリーンアップ機能(一時ファイルの削除など)に役立ちます。他のシグナルは特殊なエラー処理を行うことができますが、スクリプトを終了する必要があります(つまり、exitを呼び出します)。

あなたが説明したことは、実際にはcmdを2回実行すると思います。 1回はシグナル(SIGTERMなど)で、もう1回は出口(トラップ0)です。

これを行う適切な方法は次のようになると思います(POSIX仕様 trap を参照):

trap "rm tmpfile" 0
trap "exit 1" TERM HUP ... 

これにより、スクリプトの完了時に一時ファイルが確実に削除され、シグナルにカスタム終了ステータスを設定できます。

[〜#〜]注[〜#〜]:信号が検出されたかどうかにかかわらず、トラップ0が呼び出されます。

終了ステータスの設定に関心がない場合は、トラップ0で十分です。

19
Brandon Horsley

EXITシグナルハンドラーが2回実行されないようにするには(ほとんどの場合、希望どおりではありません)、常に無視するか、EXITシグナルハンドラー自体の定義内でリセットするように設定する必要があります。 。

プログラムで複数のシグナルハンドラが定義されているシグナルについても同様です。

# reset
trap 'excode=$?; cmd; trap - EXIT; echo $excode' EXIT HUP INT QUIT PIPE TERM

# ignore
trap 'excode=$?; trap "" EXIT; cmd; echo $excode' EXIT HUP INT QUIT PIPE TERM
22
carlo

シェル標準では、トラップされていない信号を受信したときに0のトラップを実行するかどうかは指定されていません。特に、bashとdashの動作は異なります。 trap cmd-list 0どのシグナルにもトラップが設定されていない場合、bashはSIGTERMの受信時にcmd-listを実行しますが、dashは実行しません。 trap cmd-list 0 2、bashはSIGTERMの受信時にcmd-listを1回実行し、dashはcmd-listを2回実行します。

6
William Pursell