コマンドの終了ステータスは、コマンドによって実装されますか、それともコマンドを実行するシェルプロセスによって実装されますか?

コマンドの終了ステータスは、コマンドによって実装されますか、それともコマンドを実行するシェルプロセスによって実装されますか?

バッシュマニュアルから

実行されたコマンドの終了状態waitpidシステム呼び出しまたは同等の関数によって返された値。終了状態の範囲は 0 ~ 255 ですが、シェルでは以下のように具体的に 125 より高い値を使用することもできます。シェル組み込みおよび複合コマンドの終了状態もこの範囲に制限されます。場合によっては、シェルは特定のエラーモードを示すために特別な値を使用します。

  1. 実行されたコマンドの終了状態を決定するには?

    • コマンド自体、つまりコマンドの実装が終了ステータスを決定するかどうか、つまりコマンドを実行するためのコマンドライン引数を解析することがコマンドに固有のように、実行されたコマンドの終了ステータスを決定することがコマンドの一意の属性であるかどうか。
    • このコマンドを実行するシェルプロセスは何ですか?上記の
      システムコールwaitpidは、実行されたコマンドの終了ステータスがシェルプロセスによって実装され、コマンド自体は独自の実行の終了ステータスとは関係がないようです。
  2. Bashプロセスで実行されたコマンドの終了ステータスをいつ取得できますか?

    • bashプロセスが対話型の場合にのみ、または
    • bashプロセスがインタラクティブであるか非インタラクティブであるかに関係なく? bashプロセスが非対話型の場合、bashプロセスで実行されたコマンドの終了ステータスをどのように取得しますか?

答え1

コマンド自体は、exit()システムコールの引数を介して終了ステータスを提供できます。シェル(または他のプログラム、PerlまたはPHPはどうですか?)は、system()またはシステムコールを介して子プロセスの終了ステータスを取得できます。子プロセスの状態が変わると、Unix / Linux / * BSDカーネルはSIGCHLDを親プロセスに渡す準備をします。wait()waitpid()

しかし、他の状況もあります。 SIGKILLを介して終了したプロセスは終了する機会がありません。誤ったアドレスを逆参照するプロセスは、exit()SIGSEGVシグナルハンドラがインストールされていないと呼び出すことはできません。このような場合、カーネルは、「信号によって終了する」を示すビットと、プロセス終了を引き起こした信号を含む終了状態を計算します。カーネルが計算した終了状態は、終了したプロセスの親プロセスに渡されます。

答え2

このコードは終了ステータスを設定します。

$ perl -e 'END { $? = 42 }'; echo $?
42
$ 

そうでない場合

$ perl -e 'sleep 999; END { $? = 42 }'
^C
$ echo $?
130
$ echo $((130-128))
2
$ kill -l | head -2
 1    HUP Hangup                        17   STOP Stopped (signal)         
 2    INT Interrupt                     18   TSTP Stopped
$ 

または実際に

$ perl -e '$SIG{INT}=sub{exit 7};sleep 999'                   
^C$ echo $?
7
$ 

または誰かを気持ちよく作ってはいけませんSIGKILL

そうでなければ、bashドキュメントはwaitpid16ビットステートメントを設定しましたが、bashシェル変数にそのステートメントのサブセットのみを渡すため、誤解を招く可能性があります$?。これは、シェルユーザーが結果を8ビット値(そうでない)として処理しようとするとwaitpid無知と混乱を招く可能性があります。

$ false; echo $?
1
$ perl -E 'system("false"); say $?'
256
$ perl -E 'system("false"); say $? >> 8'
1
$ 

答え3

プロセスは自己終了コードを決定します。終了すると終了コードが提供され、何も指定されていない場合は0(エラーなし)と見なされます。

対話型と非対話型の両方のシェルでは、前のコマンドの終了コードは値から取得できます$?

関連情報