シェルスクリプトの終了状態で「予約済み」コードを使用する

シェルスクリプトの終了状態で「予約済み」コードを使用する

最近このリストを見ました。特別な意味を持つ終了コード高度なBashスクリプトガイドから抜粋。彼らはこれらのコードを呼び出します予約済みそして以下をお勧めします:

上記の表によれば、終了コード1-2、126-165、および255は特別な意味を持ち、ユーザーが指定した終了パラメータには使用しないでください。

しばらく前に、次の終了ステータスコードを使用するスクリプトを作成しました。

  • 0 - 成功
  • 1 - 無効なホスト名
  • 2 - 指定されたパラメータが無効です。
  • 3 - ユーザー権限が不足しています。

スクリプトの作成時に特別な終了コードが認識されなかったため、最初のエラー条件に対して1で始まり、連続するエラータイプごとに終了ステータスが増加しました。

後で別のスクリプト(0以外の終了コードを確認できます)から呼び出すことができるようにこのスクリプトを作成しました。私は実際にこれをまだやっていません。これまでは、対話型シェルでのみスクリプトを実行しており、カスタム終了コードの使用に問題があるかどうか疑問に思いました。 Advanced Bash Scripting Guideのアドバイスはどれくらい関連性があり重要ですか?

Bashドキュメントセクションで確認されたアドバイスが見つかりません。終了ステータスBashが使用する終了コードのみをリストしますが、そのコードが何であるかは明らかではありません。予約済みまたは、独自のスクリプト/プログラムで使用しないでくださいという警告です。

答え1

いいえ終了コード特別な意味がありますが、inの値も$?特別な意味を持つことができます。

$?問題は、Bourne Shellとksh93が終了コードとエラー条件を処理し、それをシェル変数に渡す方法です。あなたがリストしたものとは異なり、次の値だけが$?特別な意味を持ちます。

  • 126バイナリがあり、実行できません。
  • 127指定したバイナリファイルが存在しません。
  • 128 終了ステータスは == 0 ですが、指定されていない問題があります。

$?また、シグナルによって中断されたプログラム用に予約されている未指定のシェルおよびプラットフォーム固有のコード範囲> 128があります。

  • Bourne Shell bashとksh88は128+セマフォを使用します。
  • ksh93は256以上の信号番号を使用します。

$?他の値はシェルの特殊値と異なる可能性があるため、問題は発生しません。

特に、1 と 2 の値は特殊な条件に使用されるのではなく、単に組み込み命令で使用する終了コードに過ぎず、組み込み命令でない場合でも同じ目的で使用されます。ポインタが次を指しているようです。Bash スクリプトガイドあなたが提供したマニュアルは、特定のコードがあなたのスクリプトで避けるべき特別な値であるかどうかについて言及せずにbashが使用するコードだけをリストするので、それは良いことではありません。

最新バージョンのBourne Shellは、プログラムが終了するのを待つwaitid()のではなく(1989年にSVr4用に導入されました)、より良いシステムコールインターフェイス(1980年にUNOSで使用されたインターフェイスと同様)を使用します。waitpid()waitid()

最新のBourne Shellバージョンエンコーディングの使用退会理由別の変数に${.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)。これにより、$?クラシックシェルでゼロと解釈されます。

答え2

プロセス終了コードの意味を標準化する試みがたくさんありました。あなたが言及したことに加えて、私は次のことも知っています。

  • BSDはsysexits.h64 から始まる値の意味を定義します。

  • GNUgrep文書の終了コード0は、少なくとも1つの一致が見つかったことを意味し、1は一致が見つからなかったことを意味し、2はI / Oエラーが発生したことを意味します。この規則は「何も間違っていませんでしたが、「何も見つかりませんでした」と「I / Oエラーが発生しました」の違いは意味があります。

  • Cライブラリ関数の多くの実装では、system終了コード127を使用してプログラムが存在しないか起動できないことを示します。

  • ウィンドウでは、NTSTATUSコード(不便に32ビットの数字スペース全体に散在している)は、終了コードとして使用することができ、特に重大な誤動作のためにプロセスが終了したことを示すコード(例えばSTATUS_STACK_OVERFLOW)。

特定のプログラムがこれらの規則に従うことを期待することはできません。ただ信頼できる規則によれば、終了コード0は成功を示し、他のコードは失敗を示す。 (C89EXIT_SUCCESSいいえ値はゼロを保証しますが、値が異なる場合でも同じように動作する必要がありますexit(0)。 )exit(EXIT_SUCCESS)

答え3

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.shexit2strexit2str.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つです)。

答え4

終了コードを記録してから1年後に戻ってスクリプトを修正する必要がある場合は、覚えていれば問題ありません。 「終了コードの保存」という概念は、通常、成功コードとして使用されるコード0と失敗コードとして使用される他のコードを除いて、実際には適用されません。

関連情報