Cでシェルアプリケーションを作成していますが、実行中のスクリプトを処理するためにSIGINTを送信しても停止しないという問題が発生しました。
同じシグナルを通常の実行可能ファイルに送信することは問題なく機能します。
例:
長時間動作するスクリプト(work.sh)を模倣するBashスクリプト:
#! /bin/bash
COUNTER=0
while true
do
((COUNTER+=1))
echo "#${COUNTER} Working..."
sleep 1
done
Cコード:
int main() {
pid_t pid = fork();
if (pid == 0) {
char* cmds[] = { "./work.sh", NULL };
if (execvp(cmds[0], cmds) == -1) {
exit(1);
}
} else {
sleep(5);
kill(pid, SIGINT);
}
return 0;
}
シグナルを送信した後、メインプロセスは終了しますが、スクリプトは印刷を続行します。
スクリプトでの信号処理はどういうわけか異なりますか?実行中のものを無視して子プロセスを停止するにはどうすればよいですか?
解決策:
work.sh
スクリプトの上に次の行を追加trap exit SIGINT
して、明示的なSIGINTハンドラーを作成します。
#! /bin/bash
trap exit SIGINT
COUNTER=0
while true
do
((COUNTER+=1))
echo "#${COUNTER} Working..."
sleep 1
done
実行work
可能ファイルを実行すると、次のように出力されます。
#1 Working...
#2 Working...
#3 Working...
#4 Working...
#5 Working...
その後、シェルに戻ります。
問題:
私はこのウェブページがUnixスタックエクスチェンジのこの質問へのコメントでリンクされているのを見つけました(完全を期すために、ここでも受け入れられた答えでリンクされたウェブページです。)これは何が起こっているかを説明するかもしれない引用です:
bashは、SIGINT / SIGQUIT配信の処理で待機および協調出口アプローチを実装する数少ないシェルの1つです。スクリプトを解釈するとき、SIGINTを受信すると、すぐには終了しませんが、代わりに、現在実行中のコマンドが戻るのを待ち、そのコマンドもそのSIGINTによって強制終了された場合にのみ終了します(SIGINTで自身を強制終了します)。たとえば、スクリプトがviを呼び出し、vi内でCtrl + Cを押してアクションをキャンセルした場合、それはスクリプトを中止する要求とは見なされないという考え方です。
したがって、スクリプトを作成していて、そのスクリプトがSIGINTを受信すると正常に終了するとします。つまり、そのスクリプトが別のbashスクリプトから呼び出された場合、Ctrl-Cは他のスクリプトを中断しなくなります。
この種の問題は、設計上SIGINTで正常に終了する実際のコマンドで見られます。
編集:
私はそれをさらによく説明する別のUnixスタックエクスチェンジの答えを見つけました。bash(1)
マニュアルページを見ると、以下も非常に説明的です。
bashによって実行される非組み込みコマンドでは、シグナルハンドラーが、シェルによってその親から継承された値に設定されます。ジョブ制御が有効になっていない場合、非同期コマンドは、これらの継承されたハンドラーに加えて、SIGINTおよびSIGQUITを無視します。
特にそれを考慮するとき:
シェルへの入力時に無視された信号は、トラップ、リセット、またはリストすることはできません。
基本的に、runningwork.sh
は別の実行環境で実行します。
組み込み関数またはシェル関数以外の単純なコマンドを実行する場合は、別の実行環境で呼び出されます。
これは無視します(明示的に存在しない場合)のシグナルハンドラが含まSIGINT
とSIGQUIT
、デフォルトでは。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加