次の Bash ループを次のように停止すると^C
:
(while true; do sleep 5; done)
しかし、次の場合はそうではありません。
(while true; do aplay test.wav; done)
私が知る限り、違いはaplay
catchとハンドラSIGINT
の違いですsleep
。
なぜこれですか? POSIXはこの動作をどこかに割り当てますか(Dashが同じことをすることがわかりました)。それでは、その理由は何ですか?なぜこのような行動が望ましいのかわかりません。実際、Bashはどのように違いを区別できますか?私は、あるプロセスが他のプロセスに信号処理方法を知らせるメカニズム(少なくともptrace
ハッカーを除く)を知らないことを認めなければなりません。/proc/
また、これを相殺する方法はないでしょうか?私はtrap 'exit 0' SIGINT
beforeループも役に立ちませんでした。
(編集する: サブシェルでループを実行することが重要です。それ以外の場合は、親シェルがループを受信しないためですSIGINT
。 )
ベストアンサー1
問題がよく説明されていますここ、ように世界教育協議会 待ってから協力して終了してください。ぜひ読んでみてください。デフォルトでは、信号はすべてのフォアグラウンドプロセス(シェルとプログラム、スリープ、または再生)で受信されます。プログラムが信号を処理しない場合、コード 130 で終了します。シェルは子プロセスが完了するのを待ち、それを見て実際にシグナルを受信すると終了します。
プログラムが信号をキャプチャすると、通常はコード1(aplayと同じ)で終了します。シェルが子プロセスを待っているときにシグナルが終了しなかったことがわかるので、シグナルがプログラム操作の正常な側面であると仮定してシェルが正常に機能します。
たとえば、aplayを処理する最善の方法は、戻りコードがゼロでないことを確認して停止することです。
(while aplay test.wav; do :; done)
上記の記事では、クリーンアップを実行するためにsigintをキャプチャしようとする善意で動作するプログラムが、そのハンドラを無効にし、正しい終了フラグセットを取得するために自分自身を再び終了する必要があることを説明します。