sys.exitとシェルのリターンコード

Pythonのsys.exitという、プロセスを終了させる関数を使ったときにちょっとはまりました。

シェルでリターンコード0は正常終了、それ以外は異常終了

シェルの慣習として、0が正常で、0以外は異常というルールがあります。
但し、0-127の間にない数を使うとこのルールが保証されるとは限らないそうです。

Pythonのドキュメントにそう書いてあります。

http://www.python.jp/doc/nightly/library/sys.html#sys.exit

整数を指定した場合、シェル等は 0 は”正常終了”、 0 以外の整数を”異常終了”として扱います。多くのシステムでは、有効な終了ステータスは 0-127 で、これ以外の値を返した場合の動作は未定義です。

sys.exitに渡した数とシェルの$?(リターンコード)が一致しない場合がある!

ボクのUbuntu11.10の環境で以下のコードを実行してみると、sys.exitには0以外の整数を渡したけどシェルの$?(直前のコマンドのリターンコードを取り出せる特殊変数)を比べると一致しない場合が確かにありました。

$ python -c "import sys; sys.exit(0)"; echo $?
0
$ python -c "import sys; sys.exit(1)"; echo $?
1
$ python -c "import sys; sys.exit(127)"; echo $?
127
$ python -c "import sys; sys.exit(128)"; echo $?
128
$ python -c "import sys; sys.exit(256)"; echo $?
0

このように、256をsys.exitに渡すとシェルは0と評価されます。

Pythonでsys.exitを使う場合はboolを使うかエラーメッセージを渡す

なので、sys.exitを使う場合は

import sys
return_code = do_something(...)
sys.exit(bool(return_code))

このようにboolで評価して引数に渡すか、

sys.exit("Failed")

などと、エラーメッセージを渡す方が良いみたいです☆

どうしてこんなことが気になったのか?

なんでこんなことを調べたかというと、自前でテストコード実行用スクリプト書いてJenkinsのジョブとして実行していたら、テストが失敗しているのに青アイコンで"SUCCESS"と画面に表示されてしまうという問題があったからです。

Jenkinsのジョブはリターンコードを見て成功・失敗を判別するので、テストコード用スクリプトがたまたまテストが失敗した場合にリターンコード256を返していてこういう結果になったんだと学びました♪♪♪