386

多数のコマンドを実行するシェル スクリプトがあります。コマンドのいずれかがゼロ以外の終了コードで終了した場合、シェルスクリプトを終了するにはどうすればよいですか?

4

9 に答える 9

502

各コマンドの後、終了コードが$?変数に含まれているため、次のようになります。

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ます。

于 2008-09-18T06:08:52.677 に答える
225

を使用する場合は、各コマンドの終了後に が更新される$?ため、各コマンドの後に確認する必要があります。$?つまり、パイプラインを実行すると、パイプラインの最後のプロセスの終了コードのみが取得されます。

別のアプローチはこれを行うことです:

set -e
set -o pipefail

これをシェルスクリプトの先頭に置くと、Bash が処理してくれるようです。以前の投稿者が指摘したように、「set -e」は、単純なコマンドで Bash をエラーで終了させます。「set -o pipefail」を使用すると、パイプライン内のコマンドでも Bash がエラーで終了します。

この問題に関するもう少しの議論については、 ここまたはここを参照してください。ビルトインの Bash マニュアル セクションは次のとおりsetです。

于 2008-09-18T06:10:19.613 に答える
54

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

于 2008-09-18T06:09:55.997 に答える
31

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

コマンド1 || 出口;
コマンド2 || 出口;

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

于 2008-09-18T06:11:37.270 に答える
26
[ $? -eq 0 ] || exit $?; # Exit for nonzero return code
于 2011-11-08T03:10:42.363 に答える
21

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

  1. cmd1の終了コードを取得するにはどうすればよいですかcmd1|cmd2

    まず、cmd1終了コードがゼロ以外である可能性があり、それでもエラーを意味しないことに注意してください。これは、たとえば、

    cmd | head -1
    

    141(またはksh93の場合は269)の終了ステータスが表示される場合がありますが、これは、 1行を読み取った後に終了したときにSIGPIPEシグナルによって中断されたcmd1ためです。cmdhead -1

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

    a。Zシェル付き(zsh):

    終了コードは、pipestatus特殊配列で提供されます。 cmd1終了コードはにあり$pipestatus[1]cmd3終了コードは $pipestatus[3]にあるので、それ$?は常にと同じ $pipestatus[-1]です。

    b。Bashを使用:

    終了コードは、PIPESTATUS特別な配列で提供されます。 cmd1終了コードはにあり${PIPESTATUS[0]}cmd3終了コードは ${PIPESTATUS[2]}にあるので、それ$?は常にと同じ ${PIPESTATUS: -1}です。

    ..。

    詳細については、Zシェルを参照してください。

于 2009-01-29T22:07:24.973 に答える
19

バッシュの場合:

# 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;
}
于 2008-09-18T06:18:53.760 に答える
11

Bash では、これは簡単です。それらを次のように結び付けるだけ&&です:

command1 && command2 && command3

ネストされたif構造を使用することもできます。

if command1
   then
       if command2
           then
               do_something
           else
               exit
       fi
   else
       exit
fi
于 2008-09-18T06:08:32.850 に答える
4
#
#------------------------------------------------------------------------------
# purpose: to run a command, log cmd output, exit on error
# usage:
# set -e; do_run_cmd_or_exit "$cmd" ; set +e
#------------------------------------------------------------------------------
do_run_cmd_or_exit(){
    cmd="$@" ;

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

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

    if [ $exit_code -ne 0 ] ; then
        do_log "ERROR $msg"
        do_log "FATAL $msg"
        do_exit "$exit_code" "$error_msg"
    else
        # If no errors occurred, just log the message
        do_log "DEBUG : cmdoutput : \"$msg\""
    fi

}
于 2012-02-19T20:47:42.987 に答える