コマンドが失敗した場合に終了する方法は?


222

私はシェルスクリプトの初心者です。メッセージが出力され、コマンドが失敗した場合はスクリプトを終了したい。私はもう試した:

my_command && (echo 'my_command failed; exit)

しかし、それは機能しません。スクリプトのこの行に続く命令を実行し続けます。私はUbuntuとbashを使用しています。


5
閉じられていない引用を、失敗/終了を引き起こす構文エラーにするつもりでしたか?そうでない場合は、例の引用符を閉じてください。
ホブ

回答:


406

試してください:

my_command || { echo 'my_command failed' ; exit 1; }

4つの変更:

  • 変更&&||
  • { }代わりに使用( )
  • ;後に紹介しexit
  • {前後のスペース}

メッセージを出力して、コマンドが失敗した場合にのみ終了する(ゼロ以外の値で終了する)必要がある||ので、は必要ありません&&

cmd1 && cmd2

成功したcmd2ときに実行されますcmd1(終了値0)。どこに

cmd1 || cmd2

失敗したcmd2ときに実行されcmd1ます(終了値がゼロ以外)。

使用すると、( )その中のコマンドを実行になり、サブシェルと呼び出すexitので、実行は元のシェルで続けて、あなたはサブシェルではなく、あなたのオリジナルのシェルを終了するには、そこに原因から。

この使用を克服するには { }

最後の2つの変更はbashで必要です。


4
「反転」しているように見えます。関数が「成功」すると0を返し、「失敗」するとゼロ以外の値を返すため、&&は前半がゼロ以外の値を返したときに評価されることが予想されます。これは、上記の答えが正しくないことを意味するのではなく、正しくありません。&&および|| スクリプトでは、戻り値ではなく成功に基づいて機能します。
CashCow

7
逆に見えますが、読んで意味があります。「このコマンドを(正常に)実行する」または「このエラーを出力して終了する」
simpleuser

2
その背後にある論理は、言語が短絡評価(SCE)を使用することです。SCEでは、式の形式が "p OR q"であり、pがtrueであると評価される場合、qを調べる理由さえありません。式が「p AND q」の形式で、pがfalseと評価された場合、qを調べる理由はありません。この理由は2つあります。1)明らかな理由により高速である、2)特定の種類のエラーを回避する(例:「if x!= 0 AND 10 / x> 5」はSCEがない場合にクラッシュする) )。このようにコマンドラインで使用できることは嬉しい副作用です。
user2635263 2015

2
STDERRにエコーすることをお勧めします{ (>&2 echo 'my_command failed') ; exit 1; }
。– rynop

127

他の回答は直接的な質問をうまくカバーしていますが、の使用にも興味があるかもしれませんset -e。これにより、失敗したコマンド(ifテストなどの特定のコンテキスト以外)はスクリプトを中止します。特定のスクリプトでは、非常に便利です。


3
残念ながら、これも非常に危険set -eです。いつ機能するか、いつ機能しないかについて、長くて難解な一連のルールがあります。(誰が実行した場合if yourfunction; then ...、その後、set -e火災の内部決してyourfunctionそのコードが考慮され、またはそれが呼び出す何でもので「チェックします」)。BashFAQ#105の演習セクションを参照してこれとその他の落とし穴について説明してください(一部は特定のシェルバージョンにのみ適用されるため、スクリプトの実行に使用される可能性があるすべてのリリースに対してテストする必要があります)。
Charles Duffy

67

また、各コマンドの終了ステータスはシェル変数$?に格納されます。これは、コマンドを実行した直後に確認できます。ゼロ以外のステータスは失敗を示します。

my_command
if [ $? -eq 0 ]
then
    echo "it worked"
else
    echo "it failed"
fi

10
これはif my_commandで置き換えることができます。ここではtestコマンドを使用する必要はありません。
Bart Sas

5
+1あなたはこの選択肢をリストすることで罰されるべきではないと思うので-それはテーブルにあるべきです-それはちょっと醜く、私の経験ではテストの性質に気づかずにその間に別のコマンドを実行するのは簡単すぎる(多分私はmは愚かです)。
Tony Delroy、2010

1
@BartSasコマンドが長い場合は、独自の行に配置することをお勧めします。スクリプトを読みやすくします。
マイケル

@Michael、行をまたがって依存関係を作成する場合ではなく、行Bを理解する前に行Aで何が起こったかを知る必要がある(または、さらに悪いことに、何かを追加しても安全だとわかる前に行Bで何が起こるかを知る必要がある)行Aの終了後に新しい)。誰かがを追加したことが何度もありましたがecho "Just finished step A"、後でチェックされる予定のがecho上書きされた$?ことを知りません。
Charles Duffy

67

スクリプト内のすべてのコマンドに対してその動作が必要な場合は、次を追加します

  set -e 
  set -o pipefail

スクリプトの最初。このオプションのペアは、コマンドがゼロ以外の終了コードで戻るたびに終了するようにbashインタープリターに指示します。

ただし、これでは終了メッセージを出力できません。


8
trapbash組み込みコマンドを使用して、終了時にコマンドを実行できます。
Gavin Smith 14

これがXYの質問に対する答えです。
jwg 2015年

5
コマンドがペアではなく独立して何を行うかを説明するのは興味深いかもしれません。特にset -o pipefail望ましい動作ではない可能性があるためです。それを指摘してくれてありがとう!
Antoine Pinsard 2017年

3
set -e信頼性、一貫性、予測性がまったくない!それを納得させるには、BashFAQ#105の演習セクション、またはin-ulm.de/~mascheck/various/set-eのさまざまなシェルの動作を比較する表を確認
Charles Duffy

14

私は次のイディオムを作り上げました:

echo "Generating from IDL..."
idlj -fclient -td java/src echo.idl
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi

echo "Compiling classes..."
javac *java
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi

echo "Done."

各コマンドの前に有益なエコーを付け、各コマンドの後に同じ
if [ $? -ne 0 ];...行を続けます。(もちろん、必要に応じてそのエラーメッセージを編集できます。)


これは関数として定義できるため、再利用できます。
Eric Wang

1
'if [$?-ne 0]; 次に... fiは '||'を書くための複雑な方法です
ケビンクライン

if ! javac *.java; then ...-なぜ$?まったく気にしないのですか?
Charles Duffy

チャールズ-私はせいぜい平凡なbashスクリプト作成者なので:)
Grant Birchmeier

10

提供されたものmy_commandが標準的に設計されている場合、つまり成功した場合に0を返し、その後&&は希望とは正反対です。あなたが欲しい||

また(、それはbashでは私には適切ではないように見えますが、私はどこにいるかは試すことができません。教えてください。

my_command || {
    echo 'my_command failed' ;
    exit 1; 
}

IIRC、{}内の各行の後にセミコロンが必要
Alex Howansky

9
@Alex:別の行にある場合はできません。
追って通知があるまで一時停止。

5

終了エラーステータスを保持し、1行に1つのコマンドを含む読み取り可能なファイルを使用する場合も使用できます。

my_command1 || exit $?
my_command2 || exit $?

ただし、これは追加のエラーメッセージを出力しません。ただし、場合によっては、失敗したコマンドによってエラーが出力されることがあります。


1
それがある理由はありませんexit $?。デフォルト値としてexit使用するだけ$?です。
Charles Duffy

@CharlesDuffyは知りませんでした。すばらしいので、さらに簡単です!
アレクスピリン

3

trapシェル組み込み(すなわち、非ゼロ復帰状態)失敗したコマンドの実行を含む捕捉信号、および他の有用な条件を可能にします。したがって、すべてのコマンドの戻りステータスを明示的にテストしたくない場合は、言うことができtrap "your shell code" ERR、コマンドがゼロ以外のステータスを返すたびにシェルコードが実行されます。例えば:

trap "echo script failed; exit 1" ERR

失敗したコマンドをキャッチする他のケースと同様に、パイプラインには特別な処理が必要です。上記はキャッチしませんfalse | true

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