web-dev-qa-db-ja.com

プロセス終了コードに基づく終了シェルスクリプト

いくつかのコマンドを実行するシェルスクリプトがあります。いずれかのコマンドがゼロ以外の終了コードで終了した場合、どうやってシェルスクリプトを終了させることができますか?

364
Mark Roddy

各コマンドの後、終了コードは$?変数にありますので、次のようになります。

ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi

$?はパイプ内の最後の要素のリターンコードのみを返すので、コード内ではパイプコマンドに注意する必要があります。

ls -al file.ext | sed 's/^/xx: /"

ファイルが存在しない場合はエラーコードを返しません(パイプラインのsed部分が実際に動作し、0を返すため)。

bashシェルは実際にその場合に役立つことができる配列を提供します、それはPIPESTATUSです。この配列には、パイプラインコンポーネントごとに1つの要素があり、${PIPESTATUS[0]}のように個別にアクセスできます。

pax> false | true ; echo ${PIPESTATUS[0]}
1

これによって、パイプライン全体ではなく、falseコマンドの結果が得られることに注意してください。あなたが適当であると思うようにあなたはまた、リスト全体を処理することができます:

pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1

パイプラインから最大のエラーコードを取得したい場合は、次のようにします。

true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc

これはそれぞれのPIPESTATUS要素を順番に調べ、前のrc値より大きかった場合はrcに格納します。

469
paxdiablo

あなたが$?を使用したいのなら、各コマンドの後に$?をチェックする必要があります。各コマンドが終了した後に更新されます。つまり、パイプラインを実行しても、パイプラインの最後のプロセスの終了コードしか取得されません。

別の方法はこれを行うことです。

set -e
set -o pipefail

これをShellスクリプトの一番上に置くと、bashがこれを処理するように見えます。前のポスターが指摘したように、 "set -e"はどんな単純なコマンドでもbashをエラーで終了させます。 "set -o pipefail"を指定すると、パイプライン内のどのコマンドでもbashがエラーで終了します。

この問題についてもう少し議論するにはここで ここ またはを見てください。 ここで はset組み込み関数のbashマニュアルセクションです。

213
Jeff Hill

"set -e"はおそらくこれを行う最も簡単な方法です。それをあなたのプログラムのコマンドの前に置くだけです。

50
Allen

パラメータなしでbashで単にexitを呼び出すと、最後のコマンドの終了コードが返されます。 ORと組み合わせると、前のコマンドが失敗した場合にのみbashはexitを呼び出す必要があります。しかし、私はこれをテストしていません。

 command1 || exit; 
 command2 ||出口;

Bashは最後のコマンドの終了コードも変数$?に格納します。

28
Arvodan
[ $? -eq 0 ] || exit $?; # exit for none-zero return code
25
chemila

http://cfaj.freeshell.org/Shell/cus-faq-2.html#11

  1. cmd1cmd1|cmd2の終了コードを取得する方法

    まず、cmd1終了コードはゼロ以外でもかまいませんが、それでもエラーを意味するわけではありません。これは例えば

    cmd | head -1
    

    cmd1の141(またはksh93では269)終了ステータスを観察するかもしれませんが、head -1が1行の読み取りの後に終了したときにcmdがSIGPIPEシグナルによって割り込まれたためです。

    パイプラインの要素の終了ステータスを知るにはcmd1 | cmd2 | cmd3

    a。 zshの場合:

    終了コードはpipestatus特殊配列に入っています。 cmd1終了コードは$pipestatus[1]にあり、cmd3終了コードは$pipestatus[3]にあるため、$?は常に$pipestatus[-1]と同じです。

    b。 bash付き:

    終了コードはPIPESTATUS特殊配列に入っています。 cmd1終了コードは${PIPESTATUS[0]}にあり、cmd3終了コードは${PIPESTATUS[2]}にあるため、$?は常に${PIPESTATUS: -1}と同じです。

    ...

    詳細については、次の リンク を参照してください。

21

bashの場合:

# this will trap any errors or commands with non-zero exit status
# by calling function catch_errors()
trap catch_errors ERR;

#
# ... the rest of the script goes here
#  

function catch_errors() {
   # do whatever on errors
   # 
   #
   echo "script aborted, because of errors";
   exit 0;
}

一言で言えば、これは簡単です。&&で結び付けるだけです。

command1 && command2 && command3

ネストしたif構文を使うこともできます。

if command1
   then
       if command2
           then
               do_something
           else
               exit
       fi
   else
       exit
fi
11
Martin W
#
#------------------------------------------------------------------------------
# run a command on failure exit with message
# doPrintHelp: doRunCmdOrExit "$cmd"
# call by:
# set -e ; doRunCmdOrExit "$cmd" ; set +e
#------------------------------------------------------------------------------
doRunCmdOrExit(){
    cmd="$@" ;

    doLog "DEBUG running cmd or exit: \"$cmd\""
    msg=$($cmd 2>&1)
    export exit_code=$?

    # if occured during the execution exit with error
    error_msg="Failed to run the command:
        \"$cmd\" with the output:
        \"$msg\" !!!"

    if [ $exit_code -ne 0 ] ; then
        doLog "ERROR $msg"
        doLog "FATAL $msg"
        doExit "$exit_code" "$error_msg"
    else
        #if no errors occured just log the message
        doLog "DEBUG : cmdoutput : \"$msg\""
        doLog "INFO  $msg"
    fi

}
#eof func doRunCmdOrExit
4
Yordan Georgiev