簡易的に条件分岐する(シェルスクリプト)

課題

複雑ではない条件分岐のために毎回 if 文を記載するのが面倒くさい。 他に条件分岐する方法は無いのか。

解決法

&& リストを利用する。

&& リストはもともと左右両方のコマンド(パイプライン)が成功したときに成功を返すことを表現する構文である。 評価は左側のコマンド(パイプライン)から実行される。 左側のコマンド(パイプライン)の結果が失敗であるとき && リスト全体が失敗になることが確定するため、そのときは右側のコマンド(パイプライン)は実行されない。 この性質によって条件分岐を表現することができる。

条件分岐を実現している例を以下に示す。

$ ls
sampledir
$ mkdir sampledir && echo "mkdir succeed"
mkdir: sampledir: File exists
$ mkdir sampledirdir && echo "mkdir succeed"
mkdir succeed
$ ls
sampledir    sampledirdir

この例では mkdir の成功・失敗を条件分岐の条件としている。

既存のディレクトリと同名のディレクトリを作成しようとすると mkdir は失敗する。 このとき mkdir 自身が File exists というエラーメッセージを出力する。 そして mkdir が失敗しているので echo は実行されない。

次に既存のディレクトリと異なる名前のディレクトリを作成しようとする。 このとき mkdir は成功するので、&&リストの右側の echo が実行されて、 mkdir succeed のメッセージが出力される。

&& リストを利用した条件分岐は if 文で書き直すことができる。 上記の例を書き直すと以下のようになる。

if mkdir sampledir; then
  echo "mkdir succeed"
fi

上記の if 文に違和感を持つ人がいるかもしれない。 if 文はたいていは以下のような形式で利用するからだ。

if [ "条件" ]; then
  "条件"が成功したときのコマンド
fi

2つの if 文の本質は同じである。 実はこの [ はコマンドであり、[ コマンドの実行結果によって条件分岐が実現されている。 [ コマンドについては別記事を執筆する。

所感

シェルスクリプトに慣れていない人はあらゆる条件分岐を if 文で実現しようとするかもしれない。 この && リストの存在とその応用方法を知っていれば、わざわざ if 文を毎回記述しなくて済む。 個人的には、事前想定と異なる場合にエラーメッセージを出力してスクリプトを異常終了させる場面で利用することが多い。

# 引数の数が想定の1個でない場合はエラーメッセージを出力して異常終了する
[ $# != 1 ] && echo "error: invalid number of args" 1>&2 && exit 1