(ジルの答えに触発されて)
ISIG
フラグセット、のための唯一の方法Child
スクリプトを取得するSIGINT
親が得ることなくがSIGINT
、それは、独自のプロセスグループであるためにです。これはset -m
オプションで実行できます。
シェルスクリプトの-m
オプションをオンにすると、Child
対話型でなくてもジョブ制御が実行されます。これにより、別のプロセスグループで実行されSIGINT
、INTR
文字が読み取られたときに親がを受信できなくなります。
ここでのPOSIXの説明-m
オプションは:
-m
このオプションは、実装がUser Portability Utilitiesオプションをサポートしている場合にサポートされます。すべてのジョブは、独自のプロセスグループで実行されます。バックグラウンドジョブの完了後、シェルがプロンプトを出す直前に、バックグラウンドジョブの終了ステータスを報告するメッセージが標準エラーに書き込まれます。フォアグラウンドジョブが停止した場合、シェルは、ジョブユーティリティによって記述された形式でメッセージを標準エラーに書き込みます。さらに、ジョブが終了以外のステータスを変更した場合(たとえば、ジョブが入力または出力のために停止した場合、またはSIGSTOPシグナルによって停止した場合)、シェルは次のプロンプトを書き込む直前に同様のメッセージを書き込む必要があります。このオプションは、対話型シェルではデフォルトで有効になっています。
-m
オプションは次のようにある-i
が、それは、シェルの動作はほぼ同じくらい変更されることはありません-i
ありません。
例:
Parent
スクリプト:
#!/bin/sh
trap 'echo "PARENT: caught SIGINT; exiting"; exit 1' INT
echo "PARENT: pid=$$"
echo "PARENT: Spawning child..."
./Child
echo "PARENT: child returned"
echo "PARENT: exiting normally"
Child
スクリプト:
#!/bin/sh -m
# ^^
# notice the -m option above!
trap 'echo "CHILD: caught SIGINT; exiting"; exit 1' INT
echo "CHILD: pid=$$"
echo "CHILD: hit enter to exit"
read foo
echo "CHILD: exiting normally"
入力を待っている間にControl+ Cを押すと、次のようになりますChild
。
$ ./Parent
PARENT: pid=12233
PARENT: Spawning child...
CHILD: pid=12234
CHILD: hit enter to exit
^CCHILD: caught SIGINT; exiting
PARENT: child returned
PARENT: exiting normally
親のSIGINT
ハンドラーが実行されないことに注意してください。
または、のParent
代わりに変更する場合はChild
、次のようにできます。
Parent
スクリプト:
#!/bin/sh
trap 'echo "PARENT: caught SIGINT; exiting"; exit 1' INT
echo "PARENT: pid=$$"
echo "PARENT: Spawning child..."
sh -m ./Child # or 'sh -m -c ./Child' if Child isn't a shell script
echo "PARENT: child returned"
echo "PARENT: exiting normally"
Child
スクリプト(通常;は必要ありません-m
):
#!/bin/sh
trap 'echo "CHILD: caught SIGINT; exiting"; exit 1' INT
echo "CHILD: pid=$$"
echo "CHILD: hit enter to exit"
read foo
echo "CHILD: exiting normally"
代替案
- フォアグラウンドプロセスグループ内の他のプロセスを変更して、の間無視
SIGINT
しChild
ます。これはあなたの質問に対処しませんが、あなたが望むものを得るかもしれません。
- 変更
Child
:
stty -g
現在の端末設定をバックアップするために使用します。
- 実行
stty -isig
の信号を生成しないようにINTR
、QUIT
とSUSP
の文字が。
- 背景には、端末入力を読み、必要に応じて信号を自分で送る(例えば、実行
kill -QUIT 0
時にControl+ \、読み込まれkill -INT $$
たときにControl+ C読まれます)。これは簡単なことではなく、Child
スクリプトやスクリプトがインタラクティブなものを意図している場合は、これをスムーズに機能させることができない場合があります。
- 終了する前に端末の設定を復元します(理想的にはのトラップから
EXIT
)。
- #2と同じですが
stty -isig
、実行するのではなく、ユーザーがヒットするのを待つEnterか、その他の特殊でないキーを待ってからkillしChild
ます。
のsetpgid
呼び出しに使用できる独自のユーティリティをC、Python、Perlなどで記述しますsetpgid()
。以下は粗雑なCの実装です:
#define _XOPEN_SOURCE 700
#include <unistd.h>
#include <signal.h>
int
main(int argc, char *argv[])
{
// todo: add error checking
void (*backup)(int);
setpgid(0, 0);
backup = signal(SIGTTOU, SIG_IGN);
tcsetpgrp(0, getpid());
signal(SIGTTOU, backup);
execvp(argv[1], argv + 1);
return 1;
}
からの使用例Child
:
#!/bin/sh
[ "${DID_SETPGID}" = true ] || {
# restart self after calling setpgid(0, 0)
exec env DID_SETPGID=true setpgid "$0" "$@"
# exec failed if control reached this point
exit 1
}
unset DID_SETPGID
# do stuff here
ksh
)。例:${ENV}
それはエラーが発生した場合、シェルはすぐに終了しません、供給され、SIGQUIT
そしてSIGTERM
無視されます。