1

私は2つのスクリプトを持っています。script1はscript2を生成し、それにシグナルを送信しSIGINTます。しかし、script2のトラップが機能していないようです?!

スクリプト 1:

#!/bin/bash
./script2 &
sleep 1
kill -SIGINT $!
sleep 2

スクリプト 2:

#!/bin/bash
echo "~~ENTRY"
trap 'echo you hit ctrl-c, waking up...' SIGINT
sleep infinity
echo "~~EXIT"

に変更./script2 &./script2て押すとCTRL+C、すべてが正常に機能します。それで、私は何を間違っていますか?

4

2 に答える 2

2

例にはいくつかの問題があります。最後に、問題の解決策があります。

  • 最初のスクリプトはwaitステートメントを欠いているように見えるため、約 3 秒後に終了します。ただしscript2、メモリに残り、実行されます。

    SIGINT シグナルを送信するプロセスを bash に自動的に判断させるにはどうすればよいですか?

  • 実際bashにはバックグラウンド プロセスで無効化SIGINT(およびSIGQUIT) され、有効化することはできません (trapコマンドを単独で実行して、設定されたトラップの現在のステータスを確認できます)。スクリプトからスクリプトにシグナル SIGINT を送信する方法を参照してください。バッシュ

    バックグラウンド プロセスであるためscript2、トラップを設定していません。両方とも無視され、バックグラウンド プロセスでトラップまたはリセットすることはできません。SIGINT SIGINTSIGQUIT

参考として、問題に関連する bash のドキュメントを次に示します。

バックグラウンド プロセスに対するプロセス グループ ID の影響 (ドキュメントのジョブ制御セクション):

[...] プロセス グループ ID が現在のターミナル プロセス グループ ID と等しいプロセスは、[..] SIGINT などのキーボード生成シグナルを受け取ります。これらのプロセスは、フォアグラウンドにあると言われています。 バックグラウンド プロセスは、プロセス グループ ID が端末のものとは異なるプロセスです。このようなプロセスは、キーボードで生成された信号の影響を受けません

SIGINTandのデフォルト ハンドラーSIGQUIT(ドキュメントのシグナルセクション):

bash によって実行される非組み込みコマンドには、シェルが親から継承した値に設定されたシグナル ハンドラーがあります。ジョブ制御が有効でない場合、非同期コマンドは、これらの継承されたハンドラーに加えて、SIGINT と SIGQUIT を無視します。

およびトラップの変更について(trap組み込みドキュメント内):

シェルに入ったときに無視されたシグナルは、トラップまたはリセットできません

解決策 1

次のように変更script1します。

#!/bin/bash
{ ./script2; } &
sleep 1
subshell_pid=$!
pid=$(ps -ax -o ppid,pid --no-headers | sed -r 's/^ +//g;s/ +/ /g' |
                           grep "^$subshell_pid " | cut -f 2 -d " ")

kill -SIGINT $pid
sleep 2
wait      ## Don't forget this.

これはどのように作動しますか ?実際には、と を使用する{とサブシェルが作成されますが、このサブシェルはバックグラウンド プロセスであるため、 で}説明した制限によって制限されます。SIGINTただし、サブシェル自体のサブプロセスはフォアグラウンドであり、バックグラウンド プロセスではありません (サブシェル スコープの場合)... 結果として、トラップまたはリセットSIGINTしてSIGQUITシグナルを送信できます。

秘訣は、サブシェルでこのサブプロセスのpidを見つけることです。ここではps、サブシェルのpidを親pidとして持つ唯一のプロセスを見つけるために使用します。

解決策 2

実際には、ジョブとして管理される直接の新しいプロセスのみが SIGINT と SIGQUIT を無視します。単純な bash 関数はそうではありません。したがって、script2コードが をソースとする関数内にある場合、これは他に何も必要としないscript1new になります。script1

#!/bin/bash
script2() {
    ## script2 code
    echo "~~ENTRY"
    trap 'echo you hit ctrl-c, waking up...' SIGINT
    sleep infinity
    echo "~~EXIT"
}
## script1 code
script2 &
sleep 1
kill -SIGINT $!
sleep 2

これも機能します。舞台裏では、ソリューション 1 と同じメカニズムが機能しています。bash 関数は構造に非常に近い{ }です。

于 2016-07-29T19:31:54.220 に答える
0

あなたが達成しようとしているscript2のは、SIGINT を受け取ったときに継続してメッセージを出力することだと思います。次に、必要です

#!/bin/bash
echo "~~ENTRY"
trap 'echo you hit ctrl-c, waking up...; CONT=true' SIGINT
CONT=false
while ! $CONT
do
   sleep 1
done
echo "~~EXIT"
于 2014-08-26T17:14:44.870 に答える