C 言語でプログラムを書き、
return 0;
return 5;
return 255;
exit(100);
_exit(0);
のように main
関数から整数値を返したり、exit
や _exit
に整数値を指定してで終了すると、その整数値の下位8ビットがプロセスの終了ステータスになる。つまり、整数 n
で終了したなら、
n & 0377
が終了ステータスになる。この終了ステータスは、シェル変数なら、$?
で取得できるし、親プロセスで wait
システムコールを使っているなら、WIFEXITED
マクロ(子プロセスが正常終了した場合に真を返す)、WEXITSTATUS
マクロ(子プロセスの終了ステータスを返す) を使って取得できる。なお、シェル変数 $?
をシェル上で出力する場合、符号なしの8ビット整数として解釈するので
return 256; // $? は 0 になる。
return 257; // $? は 1 になる。
return -1; // $? は 255 になる。
となる。
return
文や exit
, _exit
関数のような正常終了ではなく、異常終了、つまりシグナルで終了した場合、終了ステータスに相当する 8 ビットには、最上位ビットに 1 がセットされ、残りの7ビットにシグナル番号がセットされる。したがって、異常終了したプロセスのシェル変数 $?
は 128 + シグナル番号になる。たとえば、シグナル番号 1 の SIGHUP をプロセスID が 6014 のプロセスに送って
$ sleep 120 # 終了をまたずに別のシェルから kill -HUP 6014 とする。
$ echo $?
129
のように、129 = 128 + 1 になる。親プロセスで wait
システムコールを使っているなら、WIFSIGNALED
マクロ(子プロセスが異常終了したなら真を返す)、WTERMSIG
マクロ(シグナル番号を返す) で異常終了か否か、異常終了だったときのシグナル番号を調べられる。
まとめると、プロセスの終了ステータスは、0 〜 127 の範囲に制限した方がいい。128 以上や負の値にしてしまうと、シェル変数 $?
では異常終了の場合と区別できないからだ。
Python プログラムで
import sys
sys.exit(n)
で終了すると、これは C プログラムで exit(n)
で終了するのと同じになる。明示的に sys.exit(n)
を呼び出さずに終了した場合、終了ステータスが 0
で正常終了する。
python プロセス内で 8/0
のようにして例外で終了させると、プロセス自体は正常終了で、終了ステータスは 1 になる。
multiprocessing.Process
で子プロセスを作って開始した場合、その子プロセスの終了ステータスは、Process.exitcode
で取得できる。これは、
-
子プロセスが
sys.exit(n)
で終了したならn
になる。 -
子プロセスが
sys.exit(n)
を明示的に使わずに正常終了したなら、0
になる。 -
子プロセスが例外で終了したなら、
1
になる。 -
子プロセスがシグナル番号
N
により終了(異常終了)したなら、-N
になる。
したがって、Python コードで Process.exitcode
を使って子プロセスの終了状態を知らせたい場合、0
, または 2 〜 127 を使うといい。なお、親プロセスで子プロセスの Process.exitcode
を取得しないと、子プロセスがゾンビプロセスになるようだ。
実は、Python の sys.exit(n)
は、SystemExit
という BaseException
直下の例外をスローしている。プログラムがこの例外で終了した場合、Python は、 C 言語の exit(n)
で終了する。こういう例外は、プログラムでキャッチすべきではない。