UNIX/Linuxの部屋 用語集:戻り値 ステータスコード・終了ステータス・返り値


※空白区切りで AND 検索 (例:「ファイル 削除」)

用語集 戻り値 ステータスコード・終了ステータス・返り値

UNIX における戻り値について説明しよう。

コマンドの終了ステータス
ls(1)、cat(1) などのコマンドが返す値は、終了ステータス・ステータスコード・exit status などと呼ばれる。ほとんどのコマンドは以下のルールに従って実装されている。
  • 正常終了した場合は 0 を返す。
  • 異常終了時は 1 以上を返す。

個々のコマンドの終了ステータスを調べたい場合は、必ずマニュアルを参照しよう。たとえば FreeBSD の ls コマンドのマニュアルを見ると、上記のルール通り
ユーティリティ ls は、成功すると 0 で、エラーがあった場合は >0 で終了します。
となっている。しかし diff コマンドはルールから外れており、
比較結果として、違いが無かった場合は 0 を、違いが発見された場合は 1 を、何かエラーがおきた場合は 2 を返します。
とある。つまり、最終的にはマニュアルで確認するしかないということだ。

エラー値はコマンドごとにばらばらかと言うと そうではなく、ゆるいながらも一応の指針はある。エラーの種類は sysexits(3) で定義されている。以下、いくつか例をあげる。
  • 64 (EX_USAGE)
コマンド使用法エラー。オプション異常など。
  • 65 (EX_DATAERR)
入力データ異常。
  • 75 (EX_TEMPFAIL)
一時的な動作エラー。もう一度同じことをやれば成功するかもしれないエラー。~/.forward から procmail を呼び出す際に
"|IFS=' ' && exec /usr/local/bin/procmail -f- || exit 75 #username"
と書くが、この exit 75 というのは EX_TEMPFAIL を返しているわけである。

自作のシェルスクリプトやコマンドでは、最低限
  • 正常終了時は 0 を返す
  • 異常終了時は 1 (あるいはそれ以上の値) を返す
とすべきである。もし余力があれば sysexits(3) に従うとよい。

なお、終了ステータスは 0〜255 で、負の数は返せない。

システムコールの戻り値
open(2)、close(2)、read(2)、write(2)、connect(2) などのシステムコールは、正常終了なら 0、エラーなら -1 を返す。エラーの場合は識別子 errno にエラーの原因を表す値が入る。

例えば FreeBSD 4.7-RELEASE の stat(2) のマニュアルには、以下のように errno のエラーの種類が書かれている。stat(2) がこれ以外の errno を返すことは絶対にないと考えてよい (もちろん OS が違ったり、同じ FreeBSD でも異なるバージョンであればその限りではない)。

EACCES 指定されたパスには、検索が許可されていないディレクトリが含まれている
EFAULT sb か name は、プロセスに割り当てられたアドレス空間の範囲外を指している
EIO ファイルシステムでの読み書き中に入出力エラーが発生した
ELOOP パス名を変換するときに検出されたシンボリックリンクが多すぎます。
ENAMETOOLONG パス名の構成要素が 255 文字を越えているか、またはパス名全体が 1023 文字を越えている
ENOENT 指定されたファイルが存在しない
ENOTDIR パスの構成要素中にディレクトリ以外のものが含まれている

errno に意味のある値が入っているのは「システムコールを実行し、エラーが起こったとき」である。正常終了時に errno を参照しても意味のある値が入っていると期待してはいけない。

また、別のシステムコールを実行してエラーが発生した場合は、errno は上書きされる。つまり errno は「最後にエラーとなったシステムコールの原因を表す値」である。

なお、システムコールの戻り値には以下のような例外はある。
  • fork(2) は親プロセスに、生成した子プロセスのプロセス ID を返す。
  • execve(2) は成功したら返ってこないので、戻り値がない。

なお、昔は errno はグローバル変数であったが、スレッドの普及に伴い、同じプロセスでもスレッドごとに異なる errno を扱う必要が出てきた。例えば FreeBSD では errno は「スレッドごとのエラー値を管理している構造体のフィールドへのポインタ」に変わっている。

ライブラリルーチンの戻り値
fopen(3)、printf(3) などのライブラリルーチンの戻り値は、千差万別である。とにかくマニュアルを見てくださいとしか言いようがない。


頑張って書いたおすすめコンテンツ!