この短いスクリプトを考えてみましょう。 2つの信号ハンドラを設定します。 1つはforUSR1
で、もう1つはですUSR2
。その後、対話型シェルセッションを開始します。
#!/bin/sh
sigusr1_handler () {
variable=1
printf "SIGUSR1: variable is now %d\n" "$variable"
}
sigusr2_handler () {
variable=2
printf "SIGUSR2: variable is now %d\n" "$variable"
}
variable=0
printf "At beginning, variable is %d\n" "$variable"
trap 'sigusr1_handler' USR1
trap 'sigusr2_handler' USR2
/bin/sh
printf "At end, variable is %d\n" "$variable"
実行してください:
$ ./script.sh
At beginning, variable is 0
$ kill -s USR1 $PPID
$ kill -s USR2 $PPID
$ kill -s USR1 $PPID
$ exit
SIGUSR1: variable is now 1
SIGUSR2: variable is now 2
At end, variable is 2
私が最初に気づいたのは、親シェルが子シェルが終了するまで信号を処理しないことです。 POSIXで文書化した内容であることがわかったので、文書を正しく読めなかった責任は本人にあります。
2番目に気づいたのは、信号がキューに追加されていないことです。これはおそらく非常に基本的な知識ですが、見落としました。子プロセスの実行中に生成された信号は保留状態にあり、保留信号が生成されたと仮定します。再び、単に無視されます。
私の問題は私です必要対話型シェル(サブプロセス)の実行中に、シグナルを親プロセスのシグナルハンドラに転送します。子プロセスが終了した後の値に基づいて決定をしたいとし、$variable
上記のInteractiveセッションと同じ順序でシグナルが生成された場合$variable
〜しなければならないスクリプトの終わりの値は 1 です。
だから私の簡単な解決策は、サブプロセスを非同期バックグラウンドタスクとして開始することでした。
/bin/sh &
wait
(シグナルを渡すときに戻り値を確認する必要があることを知っていますが、wait
後で設定します。)
これはうまくいきません。子プロセスは直ちに終了します。
$ sh -x script.sh
+ variable=0
+ printf At beginning, variable is %d\n 0
At beginning, variable is 0
+ trap sigusr1_handler USR1
+ trap sigusr2_handler USR2
+ wait
+ /bin/sh
+ printf At end, variable is %d\n 0
At end, variable is 0
wait
(上記のトレース出力ではシェルの前に実行されているように見えますが、スクリプトでは正しい順序で実行しています。)
使用法に/bin/sh -i &
変更はありません。私は追加の試みをしてそれとそれらの組み合わせ()に/bin/sh -s
リダイレクトしましたが、役に立ちませんでした。/dev/stdin
-i -s
今私の質問は:スクリプトから非同期でインタラクティブシェルを起動する方法です。展望親プロセスは、シグナルが生成されるとすぐにシグナルを転送できるように、プロセス(つまり、入力を許可する対話型シェル)を処理しますか?それとも別のデザインがあるかもしれませんか?
答え1
勝浦さとのコメントは、私の質問に対する完全な答えです。
信号がキューに入っているかどうかはシステムによって異なります。。信号が特定の順序で転送されるという保証はありません。同じタイプのシグナルは生成された順序で転送できますが、これはシステムによって異なります(Linuxでも同様)。複数のコマンドを送信する必要がある場合は、パイプをコマンドチャネルとして使用してください。