ifステートメントを使用して終了ステータスを確認する方法


255

特定の出力をエコーするためにifステートメントで終了ステータスを確認する最良の方法は何だろうと思っていました。

と思っている

if [ $? -eq 1 ]
then
   echo "blah blah blah"
fi

私が抱えている問題は、単に終了コードが必要なため、exitステートメントがifステートメントの前にあることです。また、出口は明らかにプログラムを終了するので、私は何か間違っているのを知っています。


3
プレーゼはあなたの完全なスクリプト(または少なくともより広い範囲)を投稿します。それ以外の場合はこれで問題ありません。
RedX 2014年

5
あなたは2つの異なる場所でいくつかの特定のプログラムの起動から終了コードを使用する必要がある場合は、それを維持する必要がある-の線に沿って何かsome_program; rc=$?; if [ ${rc} -eq 1 ] .... fi ; exit ${rc}
twalberg

回答:


262

実行されるすべてのコマンドには終了ステータスがあります。

このチェックは、その行が実行される前に最後に終了したコマンドの終了ステータスを調べています。

あなたがしたい場合は、あなたのそのテストがtrueを返したときに終了するには、スクリプトを、あなたが入れた(前のコマンドが失敗した)exit 1その内側(または何でも)ifの後にブロックecho

コマンドを実行していて、以下を使用してその出力をテストしたい場合は、多くの場合より簡単です。

if some_command; then
    echo command returned true
else
    echo command returned some error
fi

または!否定のために使用を変える

if ! some_command; then
    echo command returned some error
else
    echo command returned true
fi

注どちらもそれらの心配事のようかかわらずどのようなエラーコードがあります。特定のエラーコードのみを気にすることがわかっている場合は、$?手動で確認する必要があります。


11
@ deadcell4プログラムの失敗時にシェルスクリプトを終了する必要がある場合、次のイディオムが役立ちますa_command || return 1
gboffi '31 / 10/31

10
@gboffi returnは、関数とソーススクリプトでのみ機能します。exitもう1つのケースが必要です(関数とソーススクリプトで多すぎる)。しかし、はい、特定のクリーンアップや追加の出力が必要ない場合は、これは確かに妥当なパターンです。
Etan Reisner 2014年

1
私はdash、多くの最近のLinuxディストリビューションのデフォルトの非対話型シェルは、実行されたシェルスクリプトの内部returnexit内部の区別を気にしないと言わなければなりません。dashスクリプトを使用returnしていても、スクリプトを終了します。
gboffi 2014年

最後の2つのチェックの背後にあるロジックは何ですか?if <command>終了コードが0の場合に条件が満たされるのは直観に反するようです。他の言語では、逆になります
sjw

3
重要な注意:これはパイプでは機能しません。 if ! some_command | some_other_commandsome_commandのステータスは無視されます。コマンドの2つの回避策はset -o pipefail(プログラムの他の部分の機能を変更する可能性があります)、またはifステートメントをif [[ ${PIPESTATUS[0]} -ne 0 ]]別のフォローアップコマンドとして(醜いが機能的)に移動することです。を使用している場合は、2番目のソリューションを使用するときにパイプの最後set -eに追加する|| trueこともできますif。これは、によって提供される制御フローからパイプを削除すると、パイプがすぐに終了するためです。
Alex Jansen

186

終了コード!= 0はエラーの報告に使用されることに注意してください。だから、それを行う方が良いです:

retVal=$?
if [ $retVal -ne 0 ]; then
    echo "Error"
fi
exit $retVal

の代わりに

# will fail for error codes > 1
retVal=$?
if [ $retVal -eq 1 ]; then
    echo "Error"
fi
exit $retVal

$?なので、retValでテストする必要があります。retValの割り当て後は、コマンドからの戻り値ではありません。
anr78 '19

実はそうではありません:mywiki.wooledge.org/BashFAQ/002-しかし、編集によって読みやすさが向上することに同意します。
Oo.oO

1
ただ、それが説明この投稿を見つけstackoverflow.com/questions/20157938/...
anr78

dnf check-update0(更新なし)、100(更新可能)、または1(エラー)を返します。
jww

1
@jww-まあ、それは慣習に反するのはあまり良い考えではありません(gnu.org/software/bash/manual/html_node/Exit-Status.html)。しかし、まあ、それを妨げるものは何もありません。dnf開発者がこの方法を選択した場合、それは彼らの選択です。しかし、それでも、それらを選択しても仕様が壊れることはありません:)
Oo.oO

44

$?他のパラメータと同じです。最終的にを呼び出す前に、その値を保存して使用できますexit

exit_status=$?
if [ $exit_status -eq 1 ]; then
    echo "blah blah blah"
fi
exit $exit_status

29

明示的なifステートメントの代替

最低限:

test $? -eq 0 || echo "something bad happened"

コンプリート:

EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened"; 
exit $EXITCODE

13

役立つ詳細な答えに追加するだけです:

終了コードを明示的に確認する必要がある場合は、算術演算子を次のように使用することをお勧めします(( ... ))

run_some_command
(($? != 0)) && { printf '%s\n' "Command exited with non-zero"; exit 1; }

または、次のcaseステートメントを使用します。

run_some_command; ec=$?  # grab the exit code into a variable so that it can
                         # be reused later, without the fear of being overwritten
case $ec in
    0) ;;
    1) printf '%s\n' "Command exited with non-zero"; exit 1;;
    *) do_something_else;;
esac

Bashでのエラー処理に関する関連回答:

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.