最近、高度なBashスクリプトガイドからこの特別な意味を持つ Exit Codes With Special Meanings のリストを見つけました。彼らはこれらのコードをreservedとして参照し、以下を推奨します。
上記の表によれば、終了コード1-2、126-165、および255には特別な意味があるため、ユーザー指定の終了パラメーターでは使用しないでください。
少し前に、次の終了ステータスコードを使用するスクリプトを書きました。
スクリプトを作成したとき、特別な終了コードを意識していなかったので、最初のエラー条件を1から開始し、連続するエラータイプごとに終了ステータスをインクリメントしました。
このスクリプトは、後の段階で他のスクリプト(ゼロ以外の終了コードをチェックできる)から呼び出せるようにするために作成しました。実際にはまだそれを行っていません。これまでのところ、インタラクティブシェル(Bash)からのみスクリプトを実行しており、カスタムの終了コードを使用することで何か問題が発生するかどうか疑問に思っていました。 Advanced Bash-Scripting Guideの推奨はどの程度関連性/重要ですか?
Bashのドキュメントに裏付けとなるアドバイスはありませんでした。 Exit Status のセクションには、Bashで使用される終了コードがリストされていますが、これらのいずれもreservedまたは独自のスクリプト/プログラムでそれらを使用しないよう警告します。
プロセス終了コードの意味を標準化する試みがいくつかあります。あなたが言及したものに加えて、私は知っています:
bSDには _sysexits.h
_ があり、64以上の値の意味を定義します。
GNU grep
は、終了コード0が少なくとも1つの一致が見つかったことを意味し、1は一致が見つからなかったことを意味し、2はI/Oエラーが発生したことを示します。この規則は、「何も問題はありませんでしたが、何も見つかりませんでした」と「I/Oエラーが発生しました」の区別が意味のある他のプログラムでも明らかに役立ちます。
Cライブラリ関数system
の多くの実装では、終了コード127を使用して、プログラムが存在しないか、起動に失敗したことを示しています。
Windowsでは、 NTSTATUS
コード(32ビットの数値空間全体に不便に散在している)が終了コードとして使用される可能性があり、特に、プロセスが致命的な原因で終了したことを示すコード誤動作(例:_STATUS_STACK_OVERFLOW
_)。
これらの規則のいずれかに従う特定のプログラムを当てにすることはできません。唯一のreliableルールは、終了コード0が成功で、それ以外は何らかの失敗であるということです。 (C89の_EXIT_SUCCESS
_はnotの値がゼロであることが保証されていることに注意してください。ただし、exit(0)
は同じように動作する必要があります値が同じでなくてもexit(EXIT_SUCCESS)
になります。)
いいえ終了コードには特別な意味がありますが、_$?
_の値には特別な意味がある場合があります。
Bourne Shellとksh93が処理して終了コードとエラー状況をシェル変数_$?
_に転送する方法が問題です。リストしたものとは逆に、_$?
_の次の値のみが特別な意味を持ちます。
さらに、未指定のシェルとプラットフォーム固有の_$?
_コード> 128の範囲があり、シグナルによって中断されたプログラム用に予約されています。
その他の値は、シェルの特殊な_$?
_値と区別される可能性があるため、問題にはなりません。
特に、値1と2は特別な条件では使用されませんが、組み込みコマンドでない場合でも同じように動作する組み込みコマンドによって使用される終了コードです。あなたが提供したbashスクリプトガイドへのポインタは、特定のコードかどうかコメントせずにbashで使用されるコードを一覧表示するだけなので、良いマニュアルではないようです独自のスクリプトでは使用しないでください。
Bourne Shellの新しいバージョンでは、waitid()
ではなくwaitpid()
を使用してプログラムの終了を待機し、waitid()
(1989年にSVr4で導入)はより優れたsyscallインターフェースを使用します( UNOSが1980年にすでに使用したものと同様です)。
新しいBourne Shellバージョンはexit reasonを別の変数_${.sh.code}
_/_${.sh.codename}
_にエンコードするため、${.sh.status}
_/_${.sh.termsig}
_にある終了コード、 http://schillix.sourceforge.net/man/man1/boshを参照) 1.html の場合、終了コードは特別な状態で過負荷にならず、 `waitid()を使用した結果、Bourne Shellは下位8ビットだけでなく、32ビットすべての終了コードを返すことができるようになりました。
ところで:Cプログラムやシェルスクリプトからexit(256)
や類似のものに注意しないでください。これにより、クラシックシェルでは_$?
_が0として解釈されます。
シェルスクリプトの場合、sysexist.h
という名前のシェルで予約された終了コード(プレフィックスがS_EX_
)のexit.sh
に相当するシェルをインソースすることがあります。
基本的には:
EX_OK=0 # successful termination
EX__BASE=64 # base value for error messages
EX_USAGE=64 # command line usage error
EX_DATAERR=65 # data format error
EX_NOINPUT=66 # cannot open input
EX_NOUSER=67 # addressee unknown
EX_NOHOST=68 # Host name unknown
EX_UNAVAILABLE=69 # service unavailable
EX_SOFTWARE=70 # internal software error
EX_OSERR=71 # system error (e.g., can't fork)
EX_OSFILE=72 # critical OS file missing
EX_CANTCREAT=73 # can't create (user) output file
EX_IOERR=74 # input/output error
EX_TEMPFAIL=75 # temp failure; user is invited to retry
EX_PROTOCOL=76 # remote error in protocol
EX_NOPERM=77 # permission denied
EX_CONFIG=78 # configuration error
EX__MAX=78 # maximum listed value
#System errors
S_EX_ANY=1 #Catchall for general errors
S_EX_SH=2 #Misuse of Shell builtins (according to Bash documentation); seldom seen
S_EX_EXEC=126 #Command invoked cannot execute Permission problem or command is not an executable
S_EX_NOENT=127 #"command not found" illegal_command Possible problem with $PATH or a typo
S_EX_INVAL=128 #Invalid argument to exit exit 3.14159 exit takes only integer args in the range 0 - 255 (see first footnote)
#128+n Fatal error signal "n" kill -9 $PPID of script $? returns 137 (128 + 9)
#255* Exit status out of range exit -1 exit takes only integer args in the range 0 - 255
S_EX_HUP=129
S_EX_INT=130
#...
そして、次のように生成できます:
#!/bin/sh
src=/usr/include/sysexits.h
echo "# Generated from \"$src\""
echo "# Please inspect the source file for more detailed descriptions"
echo
< "$src" sed -rn 's/^#define *(\w+)\s*(\d*)/\1=\2/p'| sed 's:/\*:#:; s:\*/::'
cat<<'EOF'
#System errors
S_EX_ANY=1 #Catchall for general errors
S_EX_SH=2 #Misuse of Shell builtins (according to Bash documentation); seldom seen
S_EX_EXEC=126 #Command invoked cannot execute Permission problem or command is not an executable
S_EX_NOENT=127 #"command not found" illegal_command Possible problem with $PATH or a typo
S_EX_INVAL=128 #Invalid argument to exit exit 3.14159 exit takes only integer args in the range 0 - 255 (see first footnote)
#128+n Fatal error signal "n" kill -9 $PPID of script $? returns 137 (128 + 9)
#255* Exit status out of range exit -1 exit takes only integer args in the range 0 - 255
EOF
$(which kill) -l |tr ' ' '\n'| awk '{ printf "S_EX_%s=%s\n", $0, 128+NR; }'
ただし、あまり使用しませんが、エラーコードを文字列形式に変換するシェル関数を使用しています。 exit2str
という名前を付けました。上記のexit.sh
ジェネレータexit.sh.sh
に名前を付けたとすると、exit2str
のコードは(exit2str.sh.sh
)で生成できます。
#!/bin/sh
echo '
exit2str(){
case "$1" in'
./exit.sh.sh | sed -nEe's|^(S_)?EX_(([^_=]+_?)+)=([0-9]+).*|\4) echo "\1\2";;|p'
echo "
esac
}"
これを対話型シェルのPS1
で使用して、各コマンドを実行した後、その終了ステータスとその文字列形式(既知の文字列形式がある場合)を確認できるようにします。
[15:58] pjump@laptop:~
(0=OK)$
[15:59] pjump@laptop:~
(0=OK)$ fdsaf
fdsaf: command not found
[15:59] pjump@laptop:~
(127=S_NOENT)$ sleep
sleep: missing operand
Try 'sleep --help' for more information.
[15:59] pjump@laptop:~
(1=S_ANY)$ sleep 100
^C
[15:59] pjump@laptop:~
(130=S_INT)$ sleep 100
^Z
[1]+ Stopped sleep 100
[15:59] pjump@laptop:~
(148=S_TSTP)$
これらを取得するには、exit2str関数のインソーサブルが必要です。
$ ./exit2str.sh.sh > exit2str.sh #Place this somewhere in your PATH
次に、それを~/.bashrc
で使用して、各コマンドプロンプトの終了コードを保存および変換し、プロンプト(PS1
)に表示します。
# ...
. exit2str.sh
Prompt_COMMAND='lastStatus=$(st="$?"; echo -n "$st"; str=$(exit2str "$st") && echo "=$str"); # ...'
PS1="$PS1"'\n($lastStatus)\$'
# ...
これは、一部のプログラムが終了コードの規則に従っているかどうかを観察する場合、終了コードの規則に従う場合、または単に終了コードの規則について学習する場合、または単に何が起こっているかを簡単に確認できる場合に非常に便利です。しばらく使用してきたので、システム指向のシェルスクリプトの多くは慣例に従っていると言えます。 EX_USAGE
は特に一般的ですが、他のコードではそれほど多くありません。怠惰な人々(私は1人です)には常に$S_EX_ANY
(1)がありますが、私は時々規則に従うようにしています。
私が見つけた最高のリファレンスはこれでした: http://tldp.org/LDP/abs/html/exitcodes.html
これによれば:
1
はエラーの一般的なキャッチオールであり、ユーザー定義のエラーに使用されることはよくあります。
2
は、構文エラーなど、Shellビルトインの誤用です。
質問に直接答えるために、スクリプトは予約済みのエラーコードを使用して問題なく動作します。エラーコード= 1/2/3に基づいてエラーを処理すると想定すると、スクリプトは期待どおりに機能します。
ただし、予約されたエラーコードを知って使用している人に遭遇すると、混乱する可能性があります。
あなたが利用できる別のオプションは、もしあなたがスクリプトがLinuxの慣習「ニュースは良いニュースではない」に従うと仮定して、エラーがあればそれをエコーしてから終了することです。
if [ $? -ne 0 ];then
echo "Error type"
exit 1
fi
私が受け取った回答(他のものを選択するのは困難でした)に基づいて、特定のタイプのエラーを示すことは有害ではありません Bashも使用する終了コードを使用します。ユーザースクリプトがこれらのエラーコードのいずれかで終了した場合、Bash(またはその他のUnixシェル)は特別な処理(例外ハンドラーの実行など)を行いません。
Advanced Bash-Scripting Guideの作成者は、BSDが終了コード(_sysexits.h
_)を標準化しようとすることに同意し、ユーザーがシェルスクリプトを作成するときに推奨しているようです、それらはすでに使用されている定義済みの終了コードと競合する終了コードを指定しません。つまり、カスタムの終了コードを64〜113の範囲の50の使用可能なステータスコードに制限します。
アイデア(およびその根拠)は高く評価しますが、スクリプトのコンシューマーが127の引用例などのエラーをチェックしている場合を除いて、アドバイスを無視しても害がないことを作成者がより明確に示した方がよいでしょう。 (_command not found
_)。
私はPOSIXが終了コードについて何を言っているかを調査しましたが、POSIX仕様はAdvanced Bash-Scripting Guideの作成者と一致しているようです。関連するPOSIX仕様を引用しました(強調は私のものです):
各コマンドには、他のシェルコマンドの動作に影響を与える可能性のある終了ステータスがあります。ユーティリティではないコマンドの終了ステータスは、このセクションに記載されています。標準ユーティリティの終了ステータスは、それぞれのセクションに記載されています。
コマンドが見つからない場合、終了ステータスは127になります。コマンド名は見つかったが、それが実行可能なユーティリティではない場合、終了ステータスは126になります。なしでユーティリティを呼び出すアプリケーションシェルを使用する場合、これらの終了ステータス値を使用して同様のエラーを報告する必要があります。
Wordの展開またはリダイレクト中にコマンドが失敗した場合、その終了ステータスはゼロより大きくなければなりません。
内部的には、コマンドがゼロ以外の終了ステータスで終了するかどうかを決定するために、シェルは、(システムインターフェースのボリュームで定義されている)wait()関数WEXITSTATUSマクロと同等のコマンドによって取得されたステータス値全体を認識します。 POSIX.1-2008)。特別なパラメーター '?'で終了ステータスを報告するとき、シェルは利用可能な終了ステータスの完全な8ビットを報告します。シグナルを受信したために終了したコマンドの終了ステータスは、128より大きいと報告されます。
他のセクションで説明されているように、特定の終了ステータス値は、特別な用途のために予約されており、shouldこれらの目的のためにのみアプリケーションで使用されます。
- _
126
_ –実行するファイルが見つかりましたが、実行可能ユーティリティではありませんでした。- _
127
_ –実行するユーティリティが見つかりませんでした。- _
>128
_ –コマンドがシグナルによって中断されました。
それだけの価値があるものについて、私は 特別な意味を持つ終了コード のリストの1つを除いてすべてを確認することができました。この終了コードの表は、詳細と Bashリファレンス に記載されているエラーコードの生成方法の例を提供するので便利です。
Bashバージョン3.2.25および4.2.46を使用して、_128 Invalid argument to exit
_エラーをスローしようとしましたが、毎回255(範囲外の終了ステータス)を受け取りました。たとえば、_exit 3.14159
_がシェルスクリプトの一部として、またはインタラクティブな子シェルで実行された場合、シェルは_255
_のコードで終了します。
_$ exit 3.14159
exit
bash: exit: 3.14159: numeric argument required
_
さらにおもしろくするために、簡単なCプログラムを実行してみましたが、この場合、exit(3)
関数は、終了する前にfloatをint(この場合は3)に変換しただけのようです。
_#include <stdlib.h>
main()
{
exit(3.14159);
}
_