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

StackOverflow https://stackoverflow.com/questions/90418

  •  01-07-2019
  •  | 
  •  

質問

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

役に立ちましたか?

解決

各コマンドの後に終了コードが表示されます。 $? 変数なので、次のようになります。

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 価値。

他のヒント

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

別のアプローチは、次のようにすることです。

set -e
set -o pipefail

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

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

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

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

command1 || exit;
command2 || exit;

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

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

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

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

    まず、次の点に注意してください cmd1 終了コードはゼロ以外である可能性がありますが、それでもエラーを意味しません。これは例えば次のような場合に起こります。

    cmd | head -1
    

    141 (ksh93 では 269) の終了ステータスが表示される可能性があります。 cmd1、しかし、それはだからです cmd SIGPIPE 信号によって中断されたときhead -1 1行読んだら終了。

    パイプラインの要素の終了ステータスを知るには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}.

    ...

    詳細については、以下を参照してください リンク.

バッシュの場合:

# 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;
}

bash ではこれは簡単で、&& で結合するだけです。

command1 && command2 && command3

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

if command1
   then
       if command2
           then
               do_something
           else
               exit
       fi
   else
       exit
fi
#
#------------------------------------------------------------------------------
# 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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top