Edited at

コマンドラインツールを書くなら知っておきたい Bash の 予約済み Exit Code

More than 1 year has passed since last update.

先日下記のリンクを教えてもらってとても参考になったので,翻訳してみました.普段コマンドラインツールの Exit Code を適当に決めている僕みたいな人は一度目を通しておいて損は無いと思います.

原文: Advanced Bash-Scripting Guide: Appendix E. Exit Codes With Special Meanings


翻訳ここから

Exit Code
意味

コメント

1
一般的なエラー全般
$ let "var 1 = 1 / 0"
ゼロ除算などのコマンドを継続できない雑多なエラー

2
(Bash のドキュメントによると)シェルビルトインな機能の誤用
$ empty_function(){}

キーワードのつけ忘れ やコマンド,または権限周りの問題(あと,diff がバイナリファイルの比較に失敗した時

126
呼び出したコマンドが実行できなかった時
$ /dev/null
パーミッションの問題かコマンドが executable でない時

127
コマンドが見つからない時
$ illegal_command

$PATH がおかしい時や typo した時などに起こる

128

exit コマンドに不正な引数を渡した時
$ exit 3.14159

exit コマンドは 0〜255 の整数だけを引数に取る

128+n
シグナル n で致命的なエラー
$ kill -9 $PPID
例では, $? は 137(128 + 9)を返す

130
スクリプトが Ctrl+C で終了
Ctrl+C
Ctrl+C はシグナル2で終了する = 128 + 2 = 130(上記)

255
範囲外の exit status
$ exit -1

exit コマンドは 0〜255 の整数だけを引数に取る

上記の表の通り,Exit Code 1, 2, 126〜165, 255 は特別な意味を持ち,スクリプトやプログラム内で exit に指定するパラメータとしては避けるべきである.とりわけ,Exit Code 127 はトラブルシューティングで混乱の元である("command not found" で終了したのか,プログラム固有のエラーなのか区別できなくなる).しかしながら,多くのスクリプトが exit 1 を一般的な実行を続行できないエラーとして使っている.Exit Code 1 は Bash の一般的なエラーを含め,とても多くのエラーで発生しうるので,デバッグの時に切り分けが大変になるだろう.

Exit Code を体系立てて定義する試みはある(/usr/include/sysexits.h)が,これは C と C++ プログラマー向けである.スクリプトに関しても同様な感じにするのが適切らしい.このドキュメントの著者はユーザ定義の Exit Code を C/C++ 標準の64〜113(もちろん成功した時は 0)に限定すべきと提案している.それにより,Exit Code からエラーの種類を特定する事ができ,トラブルシューティングが簡単になる.


Notes


  • 上記の事から,255 を超える Exit Code は予期しない問題を引き起こす可能性がある.255 を超える値を Exit Code として渡すと mod 256 な値が返される.例えば,3809 を Exit Code として返すと実際には 3809 % 256 = 225 が返される.(訳者注釈: つまり 3711 とかを返すと実際は 127 が返され,問題になりうる)


  • /usr/include/sysexits.h のアップデートにより,使っていなかった 64〜78 の値にも新しい意味が割り当てられている.今後もさらに増える可能性がある.このドキュメントの著者は上記 standard がアップデートされても例を修正しない.Exit Code の意味にオーバーラップや衝突は無いので,コンパイルされた C/C++ のバイナリやシェルスクリプトについてこれが問題になることはない.

翻訳ここまで


今まで適当にエラーは exit(1) とかやってました.守ってないプログラムも多いので実質問題は無いかもしれないですが,守っておいたほうが無難ですね.

特に 127 は,コマンドが存在しないかどうかをチェックするのに使われている場合があり,避けるべきだと思います.

また,ビルドスクリプトなどで 「Exit Code 127 で落ちたよ」と言われた時,コマンドが足りてないのかな?と目星を付けられるので便利ですね.

一応上記の Example は試してみて正しいっぽいことを確認していますが,もし間違ってる箇所とか,情報が古い箇所があれば編集リクエストなりコメントなりで教えていただけると喜びます.