いくつかのコマンドを実行するシェルスクリプトがあります。コマンドのいずれかがゼロ以外の終了コードで終了した場合、シェルスクリプトを終了させるにはどうすればよいですか?
$?
コマンドごとにの値をテストします。簡単な方法:Bashスクリプトの上部set -e
または#!/bin/bash -e
上部に配置します。
いくつかのコマンドを実行するシェルスクリプトがあります。コマンドのいずれかがゼロ以外の終了コードで終了した場合、シェルスクリプトを終了させるにはどうすればよいですか?
$?
コマンドごとにの値をテストします。簡単な方法:Bashスクリプトの上部set -e
または#!/bin/bash -e
上部に配置します。
回答:
各コマンドの後に、終了コードが$?
変数に含まれているため、次のようになります。
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
値よりも大きかった場合はそれを格納します。
ls -al file.ext || exit $?
([[]]はポータブルではありません)
[[ ]]
はでかなり移植可能であることがわかると思いますbash
、これは質問がタグ付けされているものです:-)不思議なことに十分にls
機能しないcommand.com
ため、移植性もありません。プレゼント。
PIPESTATUS
(つまり、${PIPESTATUS[0]}
最初のコマンド、${PIPESTATUS[1]}
2番目のコマンド、または${PIPESTATUS[*]}
すべての終了ステータスのリスト)
$?
直接調べる必要がほとんどないことを強調する必要があります。通常、if ls -al file.ext; then : nothing; else exit $?; fi
@ MarcHが同等であると言うようなものを望みますがls -al file.ext || exit $?
、then
or else
句が多少複雑な場合は、より保守しやすくなります。
[[ $rc != 0 ]]
あなたを与えるだろう0: not found
か1: not found
、エラーを。これはに変更する必要があります[ $rc -ne 0 ]
。またrc=$?
、取り外して使用することもでき[ $? -ne 0 ]
ます。
$?を使用したい場合は、$?なので、各コマンドの後で確認する必要があります。各コマンドが終了するたびに更新されます。つまり、パイプラインを実行すると、パイプラインの最後のプロセスの終了コードのみが取得されます。
別のアプローチはこれを行うことです:
set -e
set -o pipefail
これをシェルスクリプトの先頭に置くと、bashがこれを処理するように見えます。以前の投稿者が指摘したように、「set -e」を指定すると、bashは単純なコマンドでエラーを出して終了します。「set -o pipefail」を指定すると、bashはパイプライン内のコマンドでもエラーで終了します。
この問題に関するもう少しの議論については、ここまたはここを参照してください。 これは、組み込みのセットに関するbashのマニュアルセクションです。
PIPESTATUS
、どこでも終了コードをチェックするよりもはるかに簡単です。
#!/bin/bash -e
シェルスクリプトを開始する唯一の方法です。foo || handle_error $?
実際に終了ステータスを調べる必要がある場合など、いつでも使用できます。
「set -e
」はおそらくこれを行う最も簡単な方法です。それをプログラムのコマンドの前に置くだけです。
set -e
スクリプト内のコマンドがエラーステータスで終了し、このエラーを処理しなかった場合、スクリプトは中止されます。
set -e
100%相当set -o errexit
です。前者とは異なり、検索できます。公式ドキュメントについては、opengroup + errexitを検索してください。
http://cfaj.freeshell.org/shell/cus-faq-2.html#11
どのように私はの終了コードを取得んcmd1
でしcmd1|cmd2
まず、cmd1
終了コードがゼロ以外である可能性があり、それでもエラーを意味しないことに注意してください。これは例えば
cmd | head -1
141(またはksh93の場合は269)の終了ステータスが表示されるcmd1
場合がありますが、これは、1行を読み取った後cmd
にhead -1
終了すると、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}
です。
...
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;
}
bashではこれは簡単です、それらを&&で結びます:
command1 && command2 && command3
ネストされたif構文を使用することもできます。
if command1
then
if command2
then
do_something
else
exit
fi
else
exit
fi
if (! command)
コマンドからゼロ以外のエラーコードが予想される場合は、書き込むこともできます。
#
#------------------------------------------------------------------------------
# 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
$*
。"$@"
代わりに、スペースとワイルドカードを保持するために使用します。