DESIGN / CODE / INFRA / AI

解説

前が失敗したら次を動かしたくない:Bashの&&・||・;を使い分けよう

セミコロン、成功時の&&、失敗時の||を、書込みのない小さなBash例で比較。最後に実行した状態と、ifの代用品にする注意も整理。

前が失敗したら次を動かしたくない:Bashの&&・||・;を使い分けよう
保存リストを見る →
この記事の道しるべ 4項目

一つ目のコマンドに失敗したのに、次の処理が動いてしまった。Bashでは、コマンドを何でつなぐかによって、次を実行する条件が変わるよ。

今回はファイルを作らず、true・false・printfだけで比較する。Bashを使える端末を対象に、表示される行と終了状態を見てみよう。

セミコロンは、成功したときだけの指定ではない

コマンドを;で区切ると、通常は前の処理が終わってから次へ進む。前の終了状態が0だった場合だけ実行する、という条件は付かない。

一方、&&は左側の並びが成功した場合に右側を実行し、||は失敗した場合に右側を実行するよ。Bashでは終了状態0が成功、それ以外を失敗として扱う。

つなぎ方 次の処理へ進む条件
; 成功・失敗の条件を付けず順に進む
&& 左側が成功した場合
|| 左側が失敗した場合

小さな例をまとめて試す

カッコ内は別のシェル環境で動かす。set +eはこの中だけで、失敗のあとも結果を観察するために使い、元のシェル設定へは影響しないよ。

(
  set +e
  false; printf 'semicolon:next\n'
  false && printf 'and:next\n'
  printf 'and-status:%s\n' "$?"
  false || printf 'or:fallback\n'
  true && false || printf 'chain:fallback\n'
)

期待する表示は次の四行。

semicolon:next
and-status:1
or:fallback
chain:fallback

and:nextは表示されない。左のfalseが失敗したため、その右は実行されないんだ。and-status:1は、その並びを直後に見た終了状態だよ。

&&と||の連結を、単純なifの代わりにしない

最後の例は、最初がtrueなのにchain:fallbackが表示される。最初の条件が成功しても、次のfalseが失敗し、そのあとの||が実行されるからだよ。

成功側の処理そのものが失敗する場合もあるので、「条件 && 成功処理 || 失敗処理」をいつでもif・elseと同じだと考えないようにしよう。複雑になるなら、条件と処理をifで明示したほうが読みやすいね。

文字を次へ渡すパイプとは別

&&や||は、次のコマンドを動かす条件を扱う。標準出力を次の標準入力へ渡す|とは違う仕組みだよ。

また、&&でつないだから、すでに行った変更が失敗時に自動で元へ戻るわけでもない。更新や公開を行うスクリプトでは、事前確認、対象範囲、失敗時の復元を別に考える必要があるね。

編集部ではBashで四行の出力と、&&の右が実行されないことを確認した。本番ファイルを書き換えたり、実際のデプロイを失敗させたりはしていないよ。値の意味は終了コード、パイプ全体の判断はpipefailも参考になるね。

参考・出典

公開と変更の記録
  • :初回公開

日時は日本時間です。記載のある変更は、確認できた編集記録に基づきます。更新日の違いだけから変更内容を推測して載せることはありません。

更新・訂正の方針 →

みんなのコメント 0

感想や、試してみたことを聞かせてね。コメント・返信は承認後に公開されます。

最初のコメントをどうぞ。