それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bashで条件分岐 - if

bash で if の分岐について

bash で if の条件分岐は、C言語プログラマif 構文を一見して理解できるように書かれています。が、ちょっとコツが実は必要なのです。

bash における条件分岐

前回は、bash は条件分岐を「コマンドの終了ステータス・コード」で判別しているという話をしました。

そして、条件分岐につかう構文も「コマンド」でその終了ステータスを見て判断されます。&& を使うとコマンドの成功を条件に続けてコマンドをすることが出来ます。

前回のおさらい

だいじなので前回のおさらいをしておきます。

終了ステータスの確認方法
[[ takuya == taku* ]]; echo $? #=> 0 
終了ステータスを使ったコマンド実行
[[ takuya == taku* ]] &&  echo comand success;

さらに、コマンドは{} で複数書くことが出来るので、複数行を書くことが出来ます。

複数コマンドの実行
[[ takuya == taku* ]] && {
    echo Hello ;
    echo takuya;
    echo  sann;
}

よく見ると、この記述は C言語の if に似てませんか?わたしは似ていると思います。

この書き方のように if 文を bash で書けるとC言語系の if 文が分かる人に読みやすくなります。それが bash のif です。

bash の 条件分岐と if 文の比較

bash における if は基本的に、command && { comand ; } の構文と同じことをしています。一点だけ違うところは、 && が成功時(または失敗時)の実行に対し、 if 文は elif 節、else節が使えるというところです。

まずは、普通のif 文と比較して見ていきたいと思います。if と && がほとんど同じ書き方であると理解できると思います。

&& で書いた場合
name=takuya
[[ $name == takuya  ]] && {
    echo Hello ;
    echo takuya;
    echo  sann;
}
上記を if で書いた場合
name=takuya
if [[ $name == takuya  ]] ; then 
    echo Hello ;
    echo takuya;
    echo  sann;
fi

上記の2つは似てますよね?ほぼ同じです。 if が導入されることで 読みやすくなったと思います。if は 引数にコマンドを取るコマンドと理解してもいいかもしれません。

if 文の構文についておさらい

if 文は次のように、if comand ; then ; command ; fi で書きます。改行を入れても大丈夫。

if command ; then 
    command;
fi

ポイントは、「条件式もコマンドである」というところです。条件式がコマンドで、その終了ステータスで判断しているという点です。

else を入れた場合
if command ; then 
    command;
else 
    command; 
fi 
elif を入れた場合
if command ; then 
    command;
elif command; then
    command; 
else;
    command; 
fi 

よくある間違い

bash が「コマンド」をベースにしているので 実行するコマンドがないとエラーになります。

コマンドを実行するので、コマンドの直後でthen の直前に ; がないとエラーになります。

「if がコマンドを実行し結果で判断する」するとおぼえておけば、 ; が必要なわけも理解できると思います。; がないとすべてが引数になってしまいます・・・悲しい

if command ; then 
   # 何も書かないのだめ。コメントだけも駄目
fi

よくある間違い2

if command  then 
        command
fi

;がないと全部引数に見えてしまうお

$ if command  then command  fi 

上記の例を見れば、 ; then と then の直前に必要な理由がわかります。

then の直前の ; は省略できる。
## then の直前に改行がある
# これは動く
if command 
then 
        command
fi

bash は改行が来たらコマンドの終了と解釈する(または ; を補完したと解釈してもいい)。そのため、 then を改行から始めると ; が無くても動きます。

この辺の改行に有無も<ゆらぎ>が C言語系のプログラマbashがわかりにくい理由だと思います。

これも「if はコマンドを実行している」と強く意識していれば迷うことはないでしょう。

if 文のコマンドは正確には「コマンドリスト」

if の条件は コマンド リストで書くことが出来る。

takuya@:~$ if echo 1 ;echo 1 ; echo 1 ; then echo true; fi
1
1
1
true

複数コマンドの結果を併せて考えることも出来ます。 && でコマンドを結合すれば条件を複雑に書くことも出来ます。

次の例は&& でコマンドを結合したことがわかりやすいように { コマンド && コマンド }で括っています。

例:&& で複数コマンドの結果を条件にする
if {  grep takuya *.txt  &&   grep takuya *.php ;} ; then
    echo ok;
fi
#=> ok

まとめ

  • bash の if 文は「終了ステータスで判断する」
  • if 文は「コマンド」を実行している
  • if に書けるコマンドは複数行書くことが出来る。

このことを頭に入れておけば、if の構文が、プログラミング言語と若干違うことに戸惑いを感じること無く、そしてシンタックスエラーをもう二度と出すことはないと思います。

参考資料

  • help if
takuya@:~$ help if
if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
    条件に従ってコマンドを実行します。

    `if COMMANDS' を実行します。この終了ステータスが 0 の場合、`then COMMANDS'
    を実行します。そうでない場合は、各 `elif COMMANDS' を順番に実行し、その
    終了ステータスが 0 の場合に、関連した `then COMMANDS' を実行し、if 文が
    完了します。それ以外の場合、 `else COMMANDS' が存在する場合には実行され
    ます。文全体の終了ステータスは、最後に実行したコマンドの終了ステータスか、
    または、テストした条件に true となるものが無い場合は 0 です。

    終了ステータス:
    最後に実行したコマンドの終了ステータスを返します。