スリープ、スタンバイ、Ctrl + Cの伝播

スリープ、スタンバイ、Ctrl + Cの伝播

次のシェルスクリプトがある場合

sleep 30s

Ctrl+Cシェルスクリプトの実行中にクリックするとsleep消えます。

次のシェルスクリプトがある場合

sleep 30s &
wait

Ctrl+Cシェルスクリプトが実行されたら、[続行]をクリックしましたが、親のsleepエントリは1です。

なぜそんなことですか?バッシュはCtrl+Cすべての子供に広がりませんか?

編集:次のスクリプトがある場合

/usr/bin/Xvfb :18.0 -ac -screen 0 1180x980x24 &
wait

私はプログラムを作成しており、今回はCtrl+C基本プロセスのXvfbプロセスも終了します。

それでは、Xvfb睡眠とどう/なぜ違うのですか?

場合によってはリサイクルされており、場合initによっては死んでいました。 initが睡眠をリサイクルするのはなぜですか?なぜXvfb死なのか?

答え1

長すぎる博士。プロセスXvfbはシグナルハンドラを設定し、SIGINTそのようなシグナルが受信されると終了しますが、プロセスはそれをしsleepないので、SIGINTバイナリを実行する前にスクリプトを実行したシェルで設定したため、「無視」状態を継承しますsleep

シェルスクリプトを実行すると、ジョブ制御がオフになり、バックグラウンドプロセス(で始まるプロセス)は(無視)に設定された&同じプロセスグループでのみ実行され、標準入力は次からリダイレクトされます。SIGINTSIGQUITSIG_IGN/dev/null

これは次のために発生します。基準:

シェルが非同期リストを実行しているときにジョブ制御が無効になっている場合(set -mの説明を参照)、リストのコマンドはシェルのSIGINTおよびSIGQUITシグナルの無視(SIG_IGN)シグナル操作を継承します。

信号処理が(無視)に設定されている場合、ステータスはおよびによってSIG_IGN継承されます。fork()execve():

呼び出しプロセスイメージでデフォルトアクション(SIG_DFL)に設定されている信号は、新しいプロセスイメージでもデフォルトアクションに設定する必要があります。 SIGCHLDに加えて、呼び出しプロセスイメージが無視されるように設定された信号(SIG_IGN)も、新しいプロセスイメージによって無視されるように設定する必要があります。

答え2

~からバッシュのマニュアルページ:

バックグラウンドプロセスは、プロセスグループIDがターミナルプロセスグループIDと異なるプロセスを意味し、これらのプロセスはキーボードから生成された信号の影響を受けません。

これをさまざまな方法で処理できます。まず、リストされたジョブを終了します。

#!/bin/bash
trap 'kill $(jobs -p)' INT
sleep 30s &
wait

または、同じプロセスグループ内のすべてのプロセスにkillコマンドを送信します。

#!/bin/bash
trap 'kill 0' INT
sleep 30s &
wait

答え3

Bashは、SIGINTやSIGTERMなどの信号を現在待機しているプロセスに転送しません。

一般的な回避策は、次の例のようにトラップ待機を実行することです。

int_handler()
{
    kill -TERM "${child_pid}" > /dev/null 2>&1
}

trap 'int_handler' INT

echo "Sleeping ... "
sleep 200 &

child_pid=$!
wait ${child_pid} > /dev/null 2>&1
trap - INT
wait ${child_pid} > /dev/null 2>&1

関連情報