Linuxを起動し、小さなBashスクリプトを実行するLive CDがあります。スクリプトは、2番目のプログラム(通常はコンパイルされたC ++バイナリ)を検索して実行します。
Ctrl+を押して2番目のプログラムを中断できる必要がありますC。何しなければならない2番目のプログラムが停止し、Bashスクリプトは引き続きクリーンアップを実行します。何実際にこれにより、基本アプリケーションとBashスクリプトの両方が終了します。これは問題です。
trap
そのため、組み込みコマンドを使用してBashにSIGINTを無視するように指示します。 + Ctrl+はCC ++アプリケーションを終了しますが、Bashは引き続き実行されます。途方もない。
ああ、はい...時には「2番目のアプリケーション」が別のBashスクリプトです。そしてそれケース、Ctrl+C今すぐまったく何も。
Ctrl明らかに、これがどのように機能するのか私の理解が間違っています...ユーザーが+を押すとSIGINTを取得するプロセスをどのように制御しますかC?この信号を次に送信したいと思います。特定のプロセス。
答え1
数時間、インターネット検索の最後に答えを見つけました。
Linuxに概念があるプロセスグループ。
TTYドライバには、フォアグラウンドプロセスグループという概念があります。
Ctrl+を押すと、CTTYが
SIGINT
次に送信されます。すべてのコースフォアグラウンドプロセスグループにあります。 (あなたも見ることができますこのブログエントリ.)
したがって、コンパイルされたバイナリそしてこれを開始するスクリプトはすべて破損しています。実際、私はメインアプリケーションがこの信号を受信したいと思います。いいえスクリプトを起動します。
今、解決策は明らかです。アプリケーションを新しいプロセスグループに入れて、このTTYのフォアグラウンドプロセスグループとして作成する必要があります。明らかに、これを行うコマンドは次のとおりです。
setsid -c <applcation>
それはすべてです。ユーザーがCtrl+を押すと、CSIGINTはアプリケーション(および子アプリケーションに存在する可能性があります)に送信され、他の人には送信されません。これが私が望むものです。
setsid
独自にアプリケーションを新しいプロセスグループ(実際にはまったく新しい「セッション」、明らかにプロセスグループのセット)に配置します。この
-c
フラグを追加すると、この新しいプロセスグループは現在のTTYの「フォアグラウンド」プロセスグループになります。 (つまり、+をSIGINT
押すとCtrl表示されますC)
私はBashが新しいプロセスグループでプロセスを実行または実行しない時期について多くの矛盾する情報を見ました。 (特に「対話型」シェルと「非対話型」シェルの間に違いがあるようです。)私はあなたが使用できるいくつかの提案を見ました。賢い配管トリック...わかりません。しかし、上記の方法が私には合うようです。
答え2
開始bashスクリプトから。
2番目のプログラムのPID追跡
キャプチャ信号
SIGINTをキャプチャすると、SIGINTを2番目のプログラムPIDに送信します。
答え3
f01の説明で述べたように、SIGTERMをサブプロセスに送信する必要があります。以下は、^Cをキャプチャしてサブプロセスにシグナルを送信する方法を示すいくつかのスクリプトです。
最初は両親です。
トラップテスト
#!/bin/bash
# trap test
# Written by PM 2Ring 2014.10.23
myname=$(basename "$0")
child=sleeploop
set_trap()
{
sig=$1
msg="echo -e \"\n$myname received ^C, sending $sig to $child, $pid\""
trap "$msg; kill -s $sig $pid" SIGINT
}
trap "echo \"bye from $myname\"" EXIT
echo "running $child..."
./$child 5 &
pid=$!
# set_trap SIGINT
set_trap SIGTERM
echo "$child pid = $pid"
wait $pid
echo "$myname finished waiting"
そして今、子供です。
睡眠サイクル
#!/bin/bash
# child script for traptest
# Written by PM 2Ring 2014.10.23
myname=$(basename "$0")
delay="$1"
set_trap()
{
sig=$1
trap "echo -e '\n$myname received $sig signal';exit 0" $sig
}
trap "echo \"bye from $myname\"" EXIT
set_trap SIGTERM
set_trap SIGINT
#Select sleep mode
if false
then
echo "Using foreground sleep"
Sleep()
{
sleep $delay
}
else
echo "Using background sleep"
Sleep()
{
sleep "$delay" &
wait $!
}
fi
#Time to snooze :)
for ((i=0; i<5; i++));
do
echo "$i: sleeping for $delay"
Sleep
done
echo "$myname terminated normally"
TraptestがSIGTERMを送信するとすべてが正常に機能しますが、TraptestがSIGINTを送信するとsleeploopはこれをまったく表示しません。
sleeploopがSIGTERMをキャプチャし、スリープモードがフォアグラウンドの場合、現在のスリープモードから起きるまでその信号に応答することはできません。ただし、スリープモードがバックグラウンドの場合はすぐに反応します。