Ctrl+ などのシグナルキーCは、フォアグラウンドプロセスグループのすべてのプロセスにシグナルを送信します。
典型的なケースでは、プロセスグループはパイプラインです。たとえば、ではhead <somefile | sort
、シェルと同様に、head
実行中のプロセスと実行sort
中のプロセスが同じプロセスグループに属しているため、すべてがシグナルを受信します。バックグラウンドでジョブを実行する場合(somecommand &
)、そのジョブは独自のプロセスグループにあるため、Ctrl+を押しCても影響はありません。
timeout
プログラムは、独自のプロセスグループで自分自身を配置します。ソースコードから:
/* Ensure we're in our own group so all subprocesses can be killed.
Note we don't just put the child in a separate group as
then we would need to worry about foreground and background groups
and propagating signals between them. */
setpgid (0, 0);
タイムアウトが発生すると、timeout
それがメンバーとなっているプロセスグループを強制終了するという簡単な方法を実行します。自身を別のプロセスグループに配置しているため、その親プロセスはグループに含まれません。ここでプロセスグループを使用すると、子アプリケーションが複数のプロセスに分岐した場合、そのすべてのプロセスがシグナルを受信することが保証されます。
timeout
コマンドラインで直接実行してCtrl+ を押すCと、結果のSIGINTはtimeout
子プロセスと子プロセスの両方で受信されますが、timeout
の親プロセスであるインタラクティブシェルでは受信されません。場合はtimeout
、スクリプトから呼び出され、スクリプトを実行している唯一のシェルは、信号を受信します。timeout
それは別のプロセスグループでありますので、それを得ることはありません。
trap
組み込みのシェルスクリプトでシグナルハンドラを設定できます。残念ながら、それはそれほど簡単ではありません。このことを考慮:
#!/bin/sh
trap 'echo Interrupted at $(date)' INT
date
timeout 5 sleep 10
date
2秒後にCtrl+ を押すとC、5秒間完全に待機してから、「中断」メッセージが出力されます。これは、フォアグラウンドジョブがアクティブな間、シェルがトラップコードを実行しないためです。
これを修正するには、ジョブをバックグラウンドで実行します。シグナルハンドラーでを呼び出しkill
て、シグナルをtimeout
プロセスグループにリレーします。
#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid
bg
offg
コマンドを指定すると、実行を続けます。とにかく、あなたの最初の例と3dの例の間に違いはありますか?