説明してください:
#!/bin/bash
# This is scripta.sh
./scriptb.sh &
pid=$!
echo $pid started
sleep 3
while true
do
kill -SIGINT $pid
echo scripta.sh $$
sleep 3
done
-
#!/bin/bash
# This is scriptb.sh
trap "echo Ouch;" SIGINT
while true
do
echo scriptb.sh $$
sleep 1
done
トラップを実行すると./scripta.sh
印刷されません。 SIGINTから別の信号に切り替えると(SIGTERM、SIGUSR1を試しました)、トラップは期待どおりに「Ouch」を印刷します。どうすればこれが起こりますか?
答え1
SIGINTから別の信号に切り替えると(SIGTERM、SIGUSR1を試しました)、トラップは期待どおりに「Ouch」を印刷します。
明らかにSIGQUITを試していない場合は、SIGINTと同じように動作することがわかります。
問題は業務管理だ。
Unixの初期には、シェルがプロセスまたはパイプをバックグラウンドに入れるたびに、そのプロセスがSIGINTとSIGQUITを無視するように設定したため、ユーザーがCtrl+ C(中断)またはCtrl+(終了)を入力しても\プロセスは終了しませんでした。 。前景の仕事。タスク制御が登場したときにプロセスグループも一緒にインポートされたので、シェルでやるべきことは、バックグラウンドタスクを現在のターミナルプロセスグループでない限り新しいプロセスグループに入れることです。キーボードの入力(Ctrl+ C、Ctrl+ \ 、Ctrl+ Z(SIGTSTP))。シェルを使用すると、バックグラウンドプロセスが基本的な信号処理を維持できます。実際には、プロセスが前景Ctrlに出てくるときに+終了する必要があるかもしれません。C
ただし、非対話型シェルはジョブ制御を使用しません。歴史的な理由から、非対話型シェルはバックグラウンドプロセスに対してSIGINTとSIGQUITを無視する以前の動作に戻り、キーボードタイプの信号が送信されてもバックグラウンドプロセスを実行し続けることが合理的です。シェルスクリプトは非対話型シェルで実行されます。
trap
そして、命令の下の最後の段落を見ると大きな打撃(1)、あなたは見るでしょう
シェルに入ると無視される信号はキャプチャまたはリセットできません。
./scriptb.sh &
だからあなたから逃げたらインタラクティブシェルのコマンドプロンプトでは、対応する信号設定は変更されず(バックグラウンドに配置されていても)コマンドは期待どおりにtrap
機能します。ただし./scripta.sh
、(使用するかどうかにかかわらず)実行すると、&
非対話型シェルでスクリプトが実行されます。非対話型シェルが実行されると、割り込みを無視して終了するようにプロセスを設定します./scriptb.sh &
。scriptb
したがって、コマンドはtrap
自動的にscriptb.sh
失敗します。
答え2
いくつかの追跡を通じて:
strace -o aaa ./scripta
私たちは基本的にこれを観察することができます
read(255, "#!/bin/bash\n# this is scripta.sh"..., 153) = 153
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
lseek(255, -108, SEEK_CUR) = 45
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1ee9b7ca10) = 2483
scripta
遮断INT
と信号にも同様に適用されます。これらの設定はCHLD
(ここで呼び出されます)によって継承されます。scriptb
そして何が起こっていますか?次のように実行する場合:fork
clone
scriptb
scripta
strace -o bbb ./scriptb &
その後、シグナル関連の項目を検索しながら、以下を発見しました。
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7fb1b2e75250}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN, [], SA_RESTORER, 0x7fb1b2e75250}, {SIG_DFL, [], SA_RESTORER, 0x7fb1b2e75250}, 8) = 0
これは何もブロックされておらず、INT
信号に最初に基本処理が与えられ、次に無視されることを示します。scriptb
シェルで直接比較を実行すると、次のようにstrace
なります。
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f2c3f6d4250}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f2c3f6d4250}, {SIG_DFL, [], SA_RESTORER, 0x7f2c3f6d4250}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
rt_sigaction(SIGINT, {0x45fbf0, [], SA_RESTORER, 0x7f2c3f6d4250}, {SIG_DFL, [], SA_RESTORER, 0x7f2c3f6d4250}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [INT CHLD], 8) = 0
...
あるいは、睡眠呼出し処理を入力し、繰り返す前に決して無視されない。わかりました。デフォルトにリセットするには、scripta
との間にスペースを入れてください...scriptb
SIGINT
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ch;
while ((ch = getopt(argc, argv, "h?")) != -1) {
switch (ch) {
case 'h':
case '?':
default:
abort();
}
}
argc -= optind;
argv += optind;
if (argc < 1) abort();
signal(SIGINT, SIG_DFL);
execvp(*argv, argv);
abort();
return 1;
}
使用方法:
$ make defaultsig
cc defaultsig.c -o defaultsig
$ grep defaultsig scripta.sh
./defaultsig ./scriptb.sh &
$ ./scripta.sh
12510 started
scriptb.sh 12510
scriptb.sh 12510
scriptb.sh 12510
scripta.sh 12509
Ouch
scriptb.sh 12510
scriptb.sh 12510
scriptb.sh 12510
scripta.sh 12509
Ouch
...
はい、今はうまくいきます。しかし、なぜこれが起こるのかわかりませんbash
。バグを報告できますか?のコードはsig.c
非常に複雑に見え、他の場所ではより多くの信号処理があります。
答え3
回答いただき、時間をかけてこの問題を調査してくださった皆様に感謝します。
もう一度説明して統合します(下記で明らかになることについてお詫び申し上げます)。
1)SIGQUITも試してみましたが、SIGINTと同じように機能するという質問を追加することを忘れました。
2)これから、私は問題がこれら2つのシグナルの対話型bashの基本構成に関連しているとすでに疑っています。
3)bashと対話するときにプロンプトがあるときは何も終了または中断する必要がないため、基本的な操作は発生しません。シェルを終了するには、単に終了を入力します。
4)SIGQUITとSIGINTがジョブ制御で特別な役割を果たしているとは思わない(SIGTSTP、SIGTTOU、SIGTTINとは反対)。
5)これら2つのシグナルの対話型bashの基本構成は、バックグラウンド(非対話型)シェル(私たちの場合はscriptb.shを実行するシェル)によって継承されていることは私にはわかりません。
6) 実際、フォアグラウンドプロセスグループが SIGQUIT と SIGINT の設定を(実行したシェルから)継承しないように、IMHO はバックグラウンドプロセスグループでも同じことが起こるのが合理的です.
7)また、受け取ったキャラクターが何であれ、トラップはこれを変更しなければなりません。
8) だいたい私はthrigの意見に同意し、ここで見ているのがバグだと思う傾向があります。