コマンドが成功または失敗した場合に条件付きで何かを行う方法


283

このようなことをbashでどのように行うことができますか?

if "`command` returns any error";
then
    echo "Returned an error"
else
    echo "Proceed..."
fi

回答:


359

コマンドが成功または失敗した場合に条件付きで何かを行う方法

それはまさにbashのifステートメントが行うことです:

if command ; then
    echo "Command succeeded"
else
    echo "Command failed"
fi

コメントから情報を追加する:この場合、... 構文を使用する必要ありません。それ自体がコマンドであり、とほぼ同等です。これはおそらく、で使用する最も一般的なコマンドであり、シェルの構文の一部であるという仮定につながる可能性があります。ただし、コマンドが成功したかどうかをテストする場合は、上記のように、コマンド自体をで直接使用します。[][testifif

編集:わかりやすくするために質問を上部に引用しました(この回答はページの上部近くには表示されません)。


11
セミコロンが重要であることに注意してください。
トールビョーンラヴンアンデルセン

21
またはthen、別の行に配置することもできます。
l0b0

36
@ジョー:という意味だと思いますif ! command ; then ... ; fi[それ自体がコマンドであり、この場合は必要ありません。
キーストンプソン

20
@ジョー:私のやり方には正しいという美徳もあります。 if [ ! command ]実行されませんcommandcommand文字列として処理し、長さがゼロでないためtrueとして処理します。 [testコマンドの同義語です
キーストンプソン

5
おっと。正解です。
ジョー

133

シェルコマンドが機能する場合に発生させたい小さなことには、次の&&構文を使用できます。

rm -rf somedir && trace_output "Removed the directory"

同様に、シェルコマンドが失敗したときに発生させたい小さなことについては、次のように使用できます||

rm -rf somedir || exit_on_error "Failed to remove the directory"

または両方

rm -rf somedir && trace_output "Removed the directory" || exit_on_error "Failed to remove the directory"

これらの構成要素を非常に多く使用するのはおそらく賢明ではありませんが、場合によっては制御の流れをより明確にすることができます。


3
それらはより短く、(少なくとも一部のシェルでは)より高速です。私は一度解読しようとしただけで、これらの条件の構造と書かれたモンスターのUltrixのインストールスクリプトを思い出して身震い...
vonbrand

101

の値を確認します$?。これには、最新のコマンド/関数の実行結果が含まれています。

#!/bin/bash

echo "this will work"
RESULT=$?
if [ $RESULT -eq 0 ]; then
  echo success
else
  echo failed
fi

if [ $RESULT == 0 ]; then
  echo success 2
else
  echo failed 2
fi

11
技術的には正しい(したがって、下票を正当化しない)が、Bashのifイディオムを利用していない。キース・トンプソンの答えが好きです。
ジャンモーセン

16
このイディオムには利点があります-戻り値を保持します。全体的に見て、これはより冗長ですが、より強力だと思います。また、読みやすくなっています。
タキリアン

2
「Bash's if idiom」とは何ですか?
ノワカー

3
@Nowakerの唯一の目的がifこれを行うことであるという事実。Bashのフロー制御条件はすべて、$?背後で調べます。それが彼らの仕事です。その値を明示的に調べることは、ほとんどの場合不要であり、通常は初心者のアンチパターンです。
トリプリー

1
@lunakid終了コードを気にしないのであればif ! cmd大丈夫です。それ以外の場合、一般的な方法はelse句を使用することです。空にすることはできませんが、no-opが重要な場所thenを時々見ることができます。そこでも動作します。then : nothing; else:true
トリプリー

47

これは私のために働いた:

command && echo "OK" || echo "NOK"

場合はcommand成功し、その後、echo "OK"実行され、それが成功なので、実行が停止します。それ以外の場合&&はスキップされ、echo "NOK"実行されます。


5
あなたはそれが失敗した場合に何かをする、そして(スクリプト内のコマンドプロンプトやテストに表示する)終了コードを保存したい場合は、この操作を行うことができます command && echo "OK" || c=$?; echo "NOK"; $(exit $c)
サム・ハスラー

2
@ Sam-Hasler:そうじゃないcommand && echo "OK" || (c=$?; echo "NOK"; (exit $c))
jrw32982

9
また、echo "OK"部品自体が故障する可能性がある場合は、これがより適切ですcommand && (echo "OK"; exit 0) || (c=$?; echo "NOK"; (exit $c))
。– jrw32982

@ jrw32982、ニース、前者の構造を使用しましたが、後者は使用しませんでした。
サム・ハスラー

本当の答えはコメントにあります、みんなありがとう!
ジョシュアピンター

6

それはそれを注意すべきであるif...then...fi&&/ ||私たちは(成功時には0)をテストしたいコマンドで返される終了ステータスでアプローチのお得な情報のタイプ。ただし、一部のコマンドは、コマンドが失敗した場合、または入力を処理できなかった場合、ゼロ以外の終了ステータスを返しません。これは、これらの特定のコマンドでは通常のアプローチif&&/ ||アプローチが機能しないことを意味します。

たとえば、Linuxでは、GNU fileは引数として存在しないファイルを受け取り、find指定されたユーザーを見つけることができなかった場合、0で終了します。

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

このような場合には、我々は状況を扱うことができる1個の潜在的な方法は、読書であるstderr/ stdinメッセージ、例えばによって返されたものfileのコマンド、またはのようにコマンドの出力を解析しますfind。そのために、caseステートメントを使用できます。

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

2

私が思いつく可能性が最も多かったエラーは次のとおりです。

  • まず、値を取得します。次のようなことをするとします。

RR=$?

さて、この状況だけでなく、直面する可能性のある他の状況についても考慮してください。

定義された変数:

$ AA=1 ; if (( "10#0${AA}" == 1 )) ; then echo yes ; else echo no ; fi

回答:はい

$ AA=1 ; if (( "10#0${AA}" != 1 )) ; then echo yes ; else echo no ; fi

回答:いいえ

未定義の変数:

$ AA=1 ; if (( "10#0${BB}" == 1 )) ; then echo yes ; else echo no ; fi

回答:いいえ

$ AA=1 ; if (( "10#0${BB}" != 1 )) ; then echo yes ; else echo no ; fi

回答:はい

$ AA=1 ; if (( "10#0${BB}" == 0 )) ; then echo yes ; else echo no ; fi

回答:はい

これにより、あらゆる種類のエラーが防止されます。

おそらくすべての構文を知っていますが、ここにいくつかのヒントがあります:

  • 引用符を使用します。避けてください"blank"しますnothing
  • 変数の新しい現代表記法は${variable}です。
  • 数字の前に連結されたゼロを追加することも、「数字なし」を避けます。
  • ただし、ゼロを追加すると数値がになりbase-8ます。次のようなエラーが表示されます。
    • value too great for base (error token is "08")上記の数字のために7。それが10#出番です:
    • 10#番号をに強制しますbase-10

1

あなたはこれを行うことができます:

if ($( ping 4.4.4.4 -c1 > /dev/null )) ; then
  echo "ping response succsess!!!"
fi

9
それは機能しますが、複雑です。サブシェルのサブシェルでping pingを実行している場合、コマンドとして実行するとビューの出力がキャプチャされます。ただし、出力は常に空の文字列になる/ dev / nullにリダイレクトされるためです。したがって、サブシェルで何も実行していません。つまり、以前の終了ステータス(コマンド置換サブシェル、つまりping)が保持されます。明らかに、正しい方法はif ping ...; thenここにあります。
ステファンシャゼル

1

このスレッドの別の場所で述べたように、元の質問は基本的にそれ自体に答えます。以下は、if条件がネストされる可能性があることを示す図です。

この例ではif、ファイルが存在するかどうか、および通常のファイルかどうかを確認するために使用します。これらの条件が当てはまる場合は、サイズが0より大きいかどうかを確認してください。

#!/bin/bash

echo "Which error log are you checking today? "
read answer

if [ -f /opt/logs/$answer*.errors ]
    then
        if [ -s /opt/logs/$answer*.errors ]
            then
                echo "Content is present in the $answer error log file."
            else
                echo "No errors are present in the $answer error log file."
        fi
    else
        echo "$answer does not have an error log at this time."
fi

2
それはあなたの答えがすることですが、あなたの答えは質問に対処していません。
ジェフシャラー

@JeffSchaller、ご注意いただきありがとうございます。質問を参照するように投稿を編集しました。
quartzinquartz


-3

これは$?、最後に実行されたコマンドのステータスを示すため、この方法で簡単に実行できます。

だからそれは

#!/bin/sh

... some command ...

if [ $? == 0 ] ; then
  echo '<the output message you want to display>'
else 
  echo '<failure message>'
fi

1
Downvote:これは、ユニディオマティックであるという批判を正当に受けた以前の回答を単に言い換えているだけです。
トリプリー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.