多数のコマンドを実行するシェル スクリプトがあります。コマンドのいずれかがゼロ以外の終了コードで終了した場合、シェルスクリプトを終了するにはどうすればよいですか?
9 に答える
各コマンドの後、終了コードが$?
変数に含まれているため、次のようになります。
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
です。
" set -e
" はおそらくこれを行う最も簡単な方法です。プログラムのコマンドの前に置くだけです。
パラメーターなしで Bash で exit を呼び出すと、最後のコマンドの終了コードが返されます。と組み合わせるとOR
、前のコマンドが失敗した場合にのみ、Bash は exit を呼び出す必要があります。しかし、私はこれをテストしていません。
コマンド1 || 出口; コマンド2 || 出口;
Bash は、最後のコマンドの終了コードも変数に格納します$?
。
[ $? -eq 0 ] || exit $?; # Exit for nonzero return code
http://cfaj.freeshell.org/shell/cus-faq-2.html#11
cmd1
の終了コードを取得するにはどうすればよいですかcmd1|cmd2
まず、
cmd1
終了コードがゼロ以外である可能性があり、それでもエラーを意味しないことに注意してください。これは、たとえば、cmd | head -1
141(またはksh93の場合は269)の終了ステータスが表示される場合がありますが、これは、 1行を読み取った後に終了したときにSIGPIPEシグナルによって中断された
cmd1
ためです。cmd
head -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シェルを参照してください。
バッシュの場合:
# 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
#
#------------------------------------------------------------------------------
# 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
}