質問
いくつかのコマンドを実行するシェルスクリプトがあります。いずれかのコマンドがゼロ以外の終了コードで終了した場合、シェル スクリプトを終了するにはどうすればよいですか?
解決
各コマンドの後に終了コードが表示されます。 $?
変数なので、次のようになります。
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
終了コードを取得するにはどうすればよいですか
cmd1
でcmd1|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