試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

bash/zshのif文について

bashの対話シェルやシェルスクリプトの中で条件分岐を行う際にはif文を使用し、「if」の後ろに記述したコマンドの戻り値が0*1かどうかによって処理が分かれる。
(2008/3/27)数値や文字列の比較、ファイルやディレクトリの存在や種類のチェックなどは[[[というコマンドを使用する。「bash/zshの「[」コマンドと複合コマンド「[[」について」を参照。

if文の例

下はbash*2のシェル上で直接実行する形だが、

bash$ if zenity --question; then
> zenity --info --text "OK"
> else
> zenity --info --text "Cancel"
> fi

ここまでを入力する(各行の終わりにEnterを押す)と質問ダイアログが出て

  • OKを選択すると0が返されて*3条件を満たすため、「OK」のダイアログが出る
  • キャンセルを選択すると1が返されて条件を満たさないため、「キャンセル」のダイアログが出る

となる。
上の処理を1行で書くと

bash$ if zenity --question; then zenity --info --text "OK"; else zenity --info --text "Cancel"; fi

となり、シェルスクリプト上で書く場合は字下げ(インデント)をして

#! /bin/bash
if zenity --question; then
  zenity --info --text "OK"
else
  zenity --info --text "Cancel"
fi

のようにすると見やすい。

if文の形

条件を満たすときのみ処理を実行

「コマンドの戻り値が0のときのみ、then以下の処理を実行する」のが基本。「if」に対応した「fi」で閉じる点にも注意。

if [コマンド]; then
  [戻り値が0のときの処理]
fi

bash$ if true; then echo "TRUE"; fi
TRUE
bash$ if false; then echo "TRUE"; fi
(何も表示されない)

trueは必ず0、falseは必ず1を返すコマンド。
「!」をコマンドの手前に付けると条件が逆になり、0以外の戻り値になったときに条件が満たされる。

if ! [コマンド]; then
  [戻り値が0以外のときの処理]
fi

bash$ if ! true; then echo "TRUE"; fi
(何も表示されない)
bash$ if ! false; then echo "TRUE"; fi
TRUE

処理部分の中にif文を入れることもできるが、それに対応した「fi」で閉じることが必要。

if [コマンド1]; then
  if [コマンド2]; then
    [コマンド1,2の戻り値が0のときの処理]
  fi
fi

bash$ if true; then if true; then echo "TRUE"; fi; fi
TRUE
bash$ if true; then if false; then echo "TRUE"; fi; fi
(何も表示されない)
条件を満たさない場合の処理を記述

条件が満たされなかった場合の処理は、else以下に記述する。

if [コマンド]; then
  [戻り値が0のときの処理]
else
  [戻り値が0以外のときの処理]
fi

bash$ if true; then echo "TRUE"; else echo "FALSE"; fi
TRUE
bash$ if false; then echo "TRUE"; else echo "FALSE"; fi
FALSE

「!」をコマンドの手前に付けると条件が逆になるのは同様。

if ! [コマンド]; then
  [戻り値が0以外のときの処理]
else
  [戻り値が0のときの処理]
fi

bash$ if ! true; then echo "TRUE"; else echo "FALSE"; fi
FALSE
bash$ if ! false; then echo "TRUE"; else echo "FALSE"; fi
TRUE
多数の分岐

「if - elif - elif - ... - else - fi」で分岐されたものは、先頭のif文から順に評価して、最初にコマンドの戻り値が0になったところの処理が実行され、どれも満たさないときにelse以下の処理が実行される。elseの部分を省略した場合、どれも満たさないときにはどの処理も実行されない。
2つ目以降は「elif」という表記をすることに注意。
「!」をコマンドの手前に付けた場合、これを付けたif/elif文のみ判定が逆になる。

if [コマンド1]; then
  [コマンド1の戻り値が0のときの処理]
elif [コマンド2]; then
  [コマンド1の戻り値が0以外 かつ コマンド2の戻り値が0 のときの処理]
elif [コマンド3]; then
  [コマンド1,2の戻り値が0以外 かつ コマンド3の戻り値が0 のときの処理]
else
  [それ以外のときの処理]
fi

bash$ if true; then echo "1"; elif true; then echo "2"; elif true; then echo "3"; else echo "4"; fi
1
bash$ if false; then echo "1"; elif true; then echo "2"; elif true; then echo "3"; else echo "4"; fi
2
bash$ if false; then echo "1"; elif false; then echo "2"; elif true; then echo "3"; else echo "4"; fi
3
bash$ if false; then echo "1"; elif false; then echo "2"; elif false; then echo "3"; else echo "4"; fi
4
bash$ if false; then echo "1"; elif ! false; then echo "2"; elif false; then echo "3"; else echo "4"; fi
2
「else if」と書くとおかしくなる?

「else if」という書き方があった場合、ある条件を満たさないときの処理の先頭にif文による分岐があるものとみなされる。
例えば

if [コマンド1]; then
  [コマンド1の戻り値が0のときの処理]
else if [コマンド2]; then
  [コマンド1の戻り値が0以外 かつ コマンド2の戻り値が0のときの処理]
fi

というのは文法違反で、

if [コマンド1]; then
  [コマンド1の戻り値が0のときの処理]
else
  if [コマンド2]; then
    [コマンド1の戻り値が0以外 かつ コマンド2の戻り値が0のときの処理]
  fi
fi

とするのが正しいが、

if [コマンド1]; then
  [コマンド1の戻り値が0のときの処理]
elif [コマンド2]; then
  [コマンド1の戻り値が0以外 かつ コマンド2の戻り値が0のときの処理]
fi

という意図で間違えた書き方をしていたというケース*4もある。

条件のAND(かつ)とOR(もしくは)

複数の条件の内、前後2つの間で両方の戻り値が0である必要があるときは「&&」で結ぶ。

if [コマンド1] && [コマンド2]; then
  [コマンド1とコマンド2の両方の戻り値が0のときの処理]
fi

bash$ if true && true; then echo "TRUE"; fi
TRUE
bash$ if true && false; then echo "TRUE"; fi
(何も表示されない)

片方の戻り値が0でよいのなら「||」で結ぶ。

if [コマンド1] || [コマンド2]; then
  [コマンド1とコマンド2の片方もしくは両方の戻り値が0のときの処理]
fi

bash$ if true || false; then echo "TRUE"; fi
TRUE
bash$ if false || false; then echo "TRUE"; fi
(何も表示されない)

関連記事:

使用したバージョン:

  • bash 3.2_p17(3.2_p17-r1)
  • zsh 4.3.4(4.3.4-r1)

*1:一般的に、実行ファイルが正常に終了すると、シェルは0という値を戻り値(返り値)として受け取り、それ以外のときに別の値(具体的な値は実行ファイルによって異なる)を受け取る。1つ前に実行したコマンドの戻り値は読み取り専用特殊パラメータ「?」に入り、「${?}」もしくは「$?」という書き方で「echo $?」のようにすると表示できる

*2:zshでも同様に実行できるが、「>」の部分が「then>」「else>」といった表示になる

*3:これはzenityの仕様

*4:「elif」と書くべきところを「else if」と書いた場合