https://unix.stackexchange.com/a/230568 でのStéphaneChazelasの返信から
理想的には、SIGINTで亡くなったことを親に報告したいです(たとえば、それが別のbashスクリプトである場合、そのbashスクリプトも中断されます)。 出口130を実行することは、SIGINTを終了することと同じではありません(ただし、シェルによっては、両方のケースで$?を同じ値に設定します)。 SIGINTによる死を報告する(SIGINTが2であるシステムで最も多い)。
ただし、bash、ksh93、またはFreeBSD shでは機能しません。その130の終了ステータスはSIGINTによる終了とは見なされず、親スクリプトはそこで中止しません。
バッシュのマニュアルから:
番号がNの致命的な信号でコマンドが終了すると、Bashは終了ステータスとして値128 + Nを使用します
SIGINTのシグナル番号は2であるため、SIGINTで終了するコマンドの終了ステータスは130です。したがって、130を終了することはSIGINTの終了と同じであり、130の終了ステータスは、 SIGINT。
ありがとう。
最後のコマンドがSIGINTで終了した後に$?
に表示される130(128 + SIGINT)は、bash
などの一部のシェルによって作成された終了ステータスの簡略化された表現です。他のシェルは異なる表現を使用します(ksh93の256 + signum、yashの128 + 256 + signum、sigint
またはrc
/es
のsigquit+core
などのテキスト表現)。詳細は プロセス終了時のデフォルトの終了コード? を参照してください。
プロセスは子プロセスを待機し、そのステータスを照会できます。
_exit()
システムコール(終了コード)で正常に終了した場合これを行うには、wait()
、waitpid()
、waitid()
(廃止されたwait3()
、wait4()
も参照)またはSIGCHLDシステムコールのハンドラーのいずれかを使用します。 。
これらのシステムコールは、上記のすべての情報を返します。 (ただし、一部のシステムではwaitid()
を除き、正常に終了する子の_exit()
に渡される数値の最下位8ビットのみが使用可能です)。
しかし、bash
(およびほとんどのBourne-likeおよびcsh-likeシェル)は、すべての情報を$?
($?
は、正常に終了するプロセスの終了コードの最低8ビットであり、128 + signumでそれが殺された)の8ビット数にバンドルします。または一時停止またはトラップされ、他のすべての情報は利用できません)。したがって、明らかに、失われている情報があります。特に、$?
だけでは、プロセスが_exit(130)
を実行したのか、SIGINTで終了したのかを判別できません。
bash
は、プロセスが明らかに強制終了されていることを認識しています。たとえば、バックグラウンドプロセスが強制終了されると、次のように表示されます。
[1]+ Interrupt sleep 20
しかし、$?
では、SIGINTによって強制終了されたのか、それとも_exit(130)
を呼び出したのかを知るのに十分な情報が得られません。
ほとんどのシェルはその変換を行うので、アプリケーションは_exit(number_greater_than_127)
を何よりも行うことよりもよく知っていますが、シグナルによる死を報告します。
それでもプロセスが_exit(130)
を実行する場合、そのプロセスを待機しているプロセスは、そのプロセスが正常に終了したことを検出します。シグナルによって強制終了されたのではありません。 Cでは、WIFEXITED()
はtrueを返し、WIFSIGNALED()
はfalseを返します。
bash
自体は、プロセスがSIGINTで終了したと見なしません(SIGINTで終了した場合と同じ値を含む$?
を介してプロセスが終了したと考えても)。
したがって、それはbash
が行うSIGINTの特別な処理をトリガーしません。スクリプトでは、bash
とスクリプトで現在実行中のコマンドの両方が^C
でSIGINTを受け取ります(どちらも同じプロセスグループにあるため)。
bash
は、SIGINTを受け取ったときに、それが待機しているコマンドもSIGINTで停止した場合にのみ終了します(たとえば、スクリプト内でvi以下を実行し、^ Cを使用してvi
/にならないものを中止するとします。 less
が死ぬと、スクリプトはvi
/less
を終了して戻ったときに死ぬことはありません)。
そのコマンドbash
がSIGINTのハンドラーで_exit(130)
を待機している場合、bash
はそのSIGINTで終了しません(子が中断されたとは考えられないため、中断されたとは見なされません)。
そのため、death by SIGINTを報告する場合、そのハンドラでシグナルを受信したときに実際に追加の処理を行っていても、実際に中断されています、 _exit(130)
を実行すべきではありませんが、実際にはSIGINTを使用して自分自身を強制終了します(SIGINTのデフォルトハンドラーを復元した後)。シェルでは、それは:
trap '
extra processing
trap - INT # restore SIGINT handler
kill -s INT "$$" # report to the parent that we have indeed been
# interrupted
' INT