Kubuntu Trusty64ビットでbash
4.3を実行しています。次の2つのファイルを参照してください。
trapping-int.sh
#! /bin/bash
trap "echo Exiting" INT
cat </dev/urandom >/dev/null
echo Hello
trapping-exit.sh
#! /bin/bash
trap "echo Exiting" EXIT
cat </dev/urandom >/dev/null
echo Hello
^ Cを押すと、SIGINTをトラップするとExiting
とHello
の両方が出力されますが、EXITをトラップするとExiting
のみが出力されますが、改行が追加されます。
$ ./trapping-int
^CExiting
Hello
$ ./trapping-exit
^CExiting
$
動作が異なる理由を知りたいのですが。また、INTが^ Cで与えられていても、EXITが常に呼び出されると安全に想定できますか?
両方のスクリプトの最後の行をコメントアウトすると、トラップSIGINTはHelloを出力しなくなりますが、EXITをトラップすると余分な改行が出力されます。ここでも理由を知りたいのですが。
ありがとう!
まず、シグナルとシェルに関するいくつかの事実の要約:
キーボードでCTRL + Cを押すと、フォアグラウンドプロセスのプロセスグループ内のすべてのプロセスにSIGINTが送信されます。この場合、スクリプトを解釈するcat
コマンドとbash
プロセスの両方がSIGINTを受信することを意味します。
INT
をトラップすると、ハンドラーで明示的に終了しない限り、INT
によってプロセスが終了することはなくなりました。
EXIT
をトラップすると、引数は特定のシグナルではなく、シェルの出口で実行されます。
trapping-int.sh
の動作は、次のことが起こることがわかっているため、これらの事実を考慮すると簡単です。
cat
プロセスはSIGINTを受け取り、その実行は終了します。bash
プロセスはSIGINTを受け取り、そのシグナルハンドラーを実行して、「Exiting\n」をSTDOUT
に出力します。bash
プロセスは実行を継続し、「Hello\n」をSTDOUT
に出力します。bash
プロセスは、スクリプトの最後に到達すると終了します。trapping-exit.sh
の動作もほとんど簡単です。
cat
プロセスはSIGINTを受け取り、その実行は終了します。bash
プロセスはSIGINTを受け取り、シグナルハンドラーも存在しないため、終了します。信号を受信するとすぐに終了するため、echo
コマンドを実行/実行/実行しません。bash
プロセスが終了しているため、EXIT
ハンドラーが実行され、「Exiting\n」がSTDOUT
に出力されます。残りの質問は「改行はどこから来るのか」です。何が起こっているのかというと、bash自体が改行を出力するSIGINT
ハンドラーをインストールしていると思います。
trapping-int.sh
スクリプトでは、SIGINT
のBashのハンドラーをオーバーライドするため、余分な改行は取得されません。