bashやzshの対話シェルやシェルスクリプトの中で条件分岐を行う際にはif
文を使用する。
一般的に、実行ファイルが正常に終了するとシェルは0
という値を終了ステータス(exit status)として受け取り、それ以外のときに0
以外の値1を受け取る2が、if
の後ろに記述したコマンドの終了ステータスが0
かどうかによって処理を分けることができる。
数値や文字列の比較、ファイルやディレクトリの存在や種類のチェックなどによって分岐を行うにはtest
コマンドを用いる。
下の例を実行すると質問ダイアログが出て
“OK” を選択すると、Zenityの仕様により0
が返されて条件を満たすため、“OK” のダイアログが出る。
“キャンセル” を選択すると、1が返されて条件を満たさないため、“キャンセル” のダイアログが出る。
この例はzenity
パッケージがインストールされていない環境では正常に動作しない。GNOMEのGUI環境であれば既にインストールされている。
$ if zenity --question; then zenity --info --text "OK"; else zenity --info --text "Cancel"; fi
各行の最後でEnterを押す。fi
の行でEnterが押されるまでは入力の途中として扱われ、処理は実行されない。
$ if zenity --question
> then
> zenity --info --text "OK"
> else
> zenity --info --text "Cancel"
> fi
zshでは>
の部分がthen>
やelse>
といった表示になり、見やすくなっている。
シェルスクリプトとして書く場合は字下げ(インデント)をして記述すると見やすい。
#! /bin/sh
if zenity --question; then
zenity --info --text "OK"
else
zenity --info --text "Cancel"
fi
以下を;
または改行によって区切る。
if [コマンド...]
then [コマンドの終了ステータスが0のときの処理]
else [コマンドの終了ステータスが0以外のときの処理] (処理がない場合は省略可)
fi
if
を記述した後はif
に対応したfi
で閉じる必要がある。
“コマンドの終了ステータスが0
のときのみ、then
以下の処理を実行する” というのが基本。
if [コマンド]; then
[終了ステータスが0のときの処理]
fi
(trueコマンドは0を返すので、then以下が実行される)
$ if true; then echo "TRUE"; fi
TRUE
(falseコマンドは0以外を返すので、何もしない)
$ if false; then echo "TRUE"; fi
(何も表示されない)
true
は必ず0
、false
は必ず1
を返すコマンド。
!
をコマンドの手前に付けると条件が逆になり、終了ステータスが0
以外になったときに条件が満たされる。
if ! [コマンド]; then
[終了ステータスが0以外のときの処理]
fi
(trueコマンドは0を返し、条件が逆転しているので、何もしない)
$ if ! true; then echo "TRUE"; fi
(何も表示されない)
(falseコマンドは0以外を返し、条件が逆転しているので、else以下が実行される)
$ if ! false; then echo "TRUE"; fi
TRUE
条件が満たされた場合と満たされなかった場合の両方の処理を記述するには、後者をelse
以下に記述する。
if [コマンド]; then
[終了ステータスが0のときの処理]
else
[終了ステータスが0以外のときの処理]
fi
(trueコマンドは0を返すので、then以下が実行される)
$ if true; then echo "TRUE"; else echo "FALSE"; fi
TRUE
(falseコマンドは0以外を返すので、else以下が実行される)
$ if false; then echo "TRUE"; else echo "FALSE"; fi
FALSE
!
をコマンドの手前に付けると条件が逆になるのは同様。
if ! [コマンド]; then
[終了ステータスが0以外のときの処理]
else
[終了ステータスが0のときの処理]
fi
(trueコマンドは0を返し、条件が逆転しているので、else以下が実行される)
$ if ! true; then echo "TRUE"; else echo "FALSE"; fi
FALSE
(falseコマンドは0以外を返し、条件が逆転しているので、then以下が実行される)
$ if ! false; then echo "TRUE"; else echo "FALSE"; fi
TRUE
処理部分の中にif
文を入れることもできるが、それに対応したfi
で閉じることが必要。
if [コマンド1]; then
if [コマンド2]; then
[コマンド1,2の終了ステータスが0のときの処理]
fi
fi
(trueコマンドは0を返すので中のif文へ進み、trueコマンドは0を返すので、中のif文におけるthen以下が実行される)
$ if true; then if true; then echo "TRUE"; fi; fi
TRUE
(trueコマンドは0を返すので中のif文へ進み、falseコマンドは0以外を返すので、何もしない)
$ if true; then if false; then echo "TRUE"; fi; fi
(何も表示されない)
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
(1番目の終了ステータスが0)
$ if true; then echo "1"; elif true; then echo "2"; elif true; then echo "3"; else echo "4"; fi
1
(2番目の終了ステータスが0)
$ if false; then echo "1"; elif true; then echo "2"; elif true; then echo "3"; else echo "4"; fi
2
(3番目の終了ステータスが0)
$ if false; then echo "1"; elif false; then echo "2"; elif true; then echo "3"; else echo "4"; fi
3
(4番目の終了ステータスが0)
$ if false; then echo "1"; elif false; then echo "2"; elif false; then echo "3"; else echo "4"; fi
4
(2番目の終了ステータスが条件逆転により0)
$ if false; then echo "1"; elif ! false; then echo "2"; elif false; then echo "3"; else echo "4"; fi
2
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
という意図で間違えた書き方をしていたというケース3もある。