$ bash -c "trap \"echo INT\" INT; sleep 3" & pid=$!; sleep 1; kill -INT $pid; wait
[1] 27811
INT
[1]+ Done bash -c "trap \"echo INT\" INT; sleep 3"
$ (bash -c "trap \"echo INT\" INT; sleep 3" & pid=$!; sleep 1; kill -INT $pid; wait)
SIGINT
2番目の場合にハンドラが呼び出されない理由を説明できますか?
答え1
ジョブ制御は、ユーザーが単一のログインセッション内で複数のプロセスグループ(またはジョブ)間を移動できるようにするプロトコルを表します。
https://www.gnu.org/software/libc/manual/html_node/Job-Control.html
通常、対話型シェルでは有効になり、非対話型シェルでは無効になります。
$ echo $-; sleep 1 & fg
himBHs
[1] 84366
sleep 1
$ bash -c 'echo $-; sleep 1 & fg'
hBc
bash: line 1: fg: no job control
この場合...明らかにジョブ制御が無効になっているため、$-
信頼できません。
$ (echo $-; sleep 1 & fg)
himBHs
bash: fg: no job control
シェルはジョブを各パイプラインに関連付けます。
https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html
つまり、ジョブ制御が有効になると、各パイプラインは別々のプロセスグループで実行されます。
pgid.sh
:
#!/usr/bin/env bash
ps -o pgid= $$
$ ./pgid.sh >&2 | ./pgid.sh >&2; ./pgid.sh; ./pgid.sh & wait
93439
93439
93443
[1] 93445
93445
[1]+ Done ./a.sh
$ (./pgid.sh >&2 | ./pgid.sh >&2; ./pgid.sh; ./pgid.sh & wait)
93749
93749
93749
93749
タスクの1つはフォアグラウンドタスクで、残りはバックグラウンドタスクです。
バックグラウンドタスクがありますしてはいけないそれらを始めた殻に縛られています。シェルを終了すると、引き続き実行されます。したがって、SIGINT
基本的に中断してはいけません。ジョブ制御が有効になると、バックグラウンドジョブは別のプロセスグループで実行されるため、このジョブは自動的に実行されます。ジョブ制御が無効になると、非同期bash
コマンドは無視され、そのSIGINT
コマンド(スクリプトの場合bash
)はそれを上書きすることはできません。
つまり、ここでは次のようになります。
$ bash -c "trap 'echo INT' INT; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait
バックグラウンドジョブ(bash -c "trap 'echo INT' INT; sleep 3"
)は、ジョブ制御が有効になっている対話型シェルによって実行されます。結果バックグラウンドジョブが受信されましたSIGINT
。
これをジョブ制御なしで非対話型シェルでラップすると、次のようになります。
$ (bash -c "trap 'echo INT' INT; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait)
bash -c "trap 'echo INT' INT; sleep 3"
無視されSIGINT
、trap ... INT
また無視されます。
これは次のように確認できます。
$ bash -c "trap 'echo INT' INT; trap; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait
[1] 293631
trap -- 'echo INT' SIGINT
trap -- '' SIGFPE
INT
[1]+ Done bash -c "trap 'echo INT' INT; trap; sleep 3"
$ (bash -c "trap 'echo INT' INT; trap; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait)
trap -- '' SIGINT
trap -- '' SIGQUIT
trap -- '' SIGFPE
$ bash -c 'ps -o pid,ignored,comm,args -p $$' & wait
[1] 345833
PID IGNORED COMMAND COMMAND
345833 0000000000000000 ps ps -o pid,ignored,comm,args -p 345833
[1]+ Done bash -c 'ps -o pid,ignored,comm,args -p $$'
$ (bash -c 'ps -o pid,ignored,comm,args -p $$' & wait)
PID IGNORED COMMAND COMMAND
345629 0000000000000006 ps ps -o pid,ignored,comm,args -p 345629
関連する引用:
Bashによって実行される非組み込みコマンドは、シグナルハンドラをシェルが親から継承した値に設定します。ジョブ制御が無効になると、非同期コマンドは無視され
SIGINT
ます。SIGQUIT
これらの継承されたハンドラに加えて、コマンドの置き換えの結果として実行されるコマンドは、キーボードから生成されたジョブ制御信号とを無視しますSIGTTIN
。SIGTTOU
SIGTSTP
https://www.gnu.org/software/bash/manual/html_node/Signals.html
シェルに入ると無視される信号はキャプチャまたはリセットできません。
https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-trap
ジョブ制御とは、プロセスの実行を選択的に停止(一時停止)し、後で実行を再開(再開)する機能を指します。ユーザーは通常、オペレーティングシステムカーネルのターミナルドライバとBashが提供するインタラクティブインタフェースを介してこの機能を使用します。
シェルはジョブを各パイプラインに関連付けます。これ
jobs
には、コマンドを使用して一覧表示できる現在実行中の作業テーブルがあります。 Bashがジョブを非同期的に開始すると、次の行が印刷されます。[1] 25647
このジョブがジョブ番号であり、
1
このジョブに関連付けられているパイプラインの最後のプロセスのプロセスIDがあることを示します25647
。単一パイプライン内のすべてのプロセスは同じタスクのメンバーです。 Bash は、ジョブ抽象化をジョブ制御の基礎として使用します。タスク制御ユーザーインターフェースの実装を容易にするために、オペレーティングシステムは現在の端末プロセスグループIDの概念を維持しています。このプロセスグループのメンバー(現在の端末のプロセスグループIDと同じプロセスグループIDを持つプロセス)は、キーボードから生成された信号を受け取ります
SIGINT
。これらのプロセスは前景にあると言われています。バックグラウンドプロセスは、プロセスグループIDが端末プロセスグループIDと異なるプロセスである。これらのプロセスはキーボードから生成された信号の影響を受けません。フォアグラウンドプロセスのみが端末からデータを読み取ることができ、ユーザーが指定した場合はstty tostop
端末に書き込むことができます。端末から読み取り(stty tostop
または有効な場合は書き込み)を試みるバックグラウンドプロセスは、カーネルの端末ドライバから送信された()信号を持ち、捕捉されない限り停止しSIGTTIN
ます。SIGTTOU
https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html