それマグで!

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

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

bashの条件分岐 : if 以前の話

bashの使い方:条件分岐の話

if / while / until / case の話をしようと思っています。とても大変なので、できるだけシンプルにストーリーにしてわかりやすく書こうと思っています。

最初は条件分岐の話です。条件分岐はbashの理解に大きな影響を与える話なのですが、書籍でも皆によく読み飛ばされてて残念な感じ。わたしも読み飛ばしてて後で痛い目にあった。

条件分岐の話をうまく書けてるかどうかは、bashの紹介記事や書籍の出来を大きく左右すると思います。

条件分岐以前の話

こんな話が出てきます。

  • 終了ステータス・コード
  • && による条件分岐
  • || による条件分岐
  • if を使わない複数行条件分岐

条件分岐 if 以前の話

bash でif条件分岐をするまえに、知っておくべき必須知識があります。

シェルの条件分岐は終了ステータスで判断するということです。

シェルがコマンドを実行すると、実行結果は終了ステータス・コードで返されます。true / falseではありません。

他のプログラミング言語が true/false で判断するの対し、シェルでは終了ステータスが0か否かで判断されます。

大事なので2回言いました。

終了ステータスについて

終了ステータスは、0かそれ以外で判断されます。

終了ステータス 終了で意味 条件での意味
0 正常終了 true
1 異常終了 false
2 異常終了 false
- 中略 false
N 異常終了 false

は 正常終了で、正常終了なのでtrue と判断されます。0以外は異常終了です。通常は正の整数で表現されます。

とくに、1がFalseで0がTrue になるところは特徴的なので忘れないでください。絶対に忘れないでください。

終了ステータス 終了で意味 条件での意味
N == 0 正常終了 true
N >0 異常終了 false

終了ステータスの確認

終了ステータスは、$? の変数で確認できます。。 $? に直前に実行されたコマンドの実行結果が格納されます。

つねに終了ステータス0を返す /bin/true を用いて調べてみましょう。

この1行で書く書き方を覚えておいてください。2行で書くのは不便なのでここから先は1行で書きます。

例:正常終了(1)
$ /usr/bin/true
$ echo $? #=> 0
例:正常終了(2)・・・1行記述
$ /usr/bin/true ; echo $? #=> 0
例:異常終了
$ /usr/bin/false; echo $? #=> 1
例:コマンドが見つからない
$ NoExistCommand ; echo $? 
-bash: NoExistCommand: コマンドが見つかりません
127

終了ステータスを確認する方法を覚えておく。

紹介した終了ステータスを覚えておく方法は、覚えておくと便利です。

次の形で確認するとお覚えておくといいでしょう。

$ COMMAND ; echo $?

シェルスクリプトif の条件がただしいか。これらの目的のため、切り出して確認することも多いです。

このようにシェルスクリプトでは、if の中身だけを実行することが可能です。

例:if 条件を確認する
$ [[  $name = takuya ]] ; echo $?

原始的な条件分岐&&||

まだif は使いません。

&& で 終了ステータスを活用する AND条件を書くことが出来ます。

一番シンプルな条件分岐が && による条件分岐です。今回はif の条件分岐に入る以前の話です。if は使いません。

&& だけでも十分なコマンドの分岐を書くことが出来ます。

&& と終了ステータスを使って、コマンドを続けて実行する方法を見ておきます。

COMMAND1 && COMMAND2

これは、COMMAND1が実行され、正常終了(戻り値0)になったら、COMMAND2 が実行されます。

また、 COMMAND は 複数行で構成することもできるので { } を使って次のように書くことも出来ます。

COMMAND1 &&  { COMMAND2-1; COMMAND2-2; }

次のサンプルでは、ディレクトリの *.jpg を列挙して移動します。これはjpg ファイルがない場合で、ls *.jpg が失敗すると、&& 以降 のコマンドは実行されません。。

この書き方は testコマンドと併せて使うと便利です。この程度なら、まだ if 無くても大丈夫です。

test コマンドは、条件分岐のチェックパターンでまた紹介します。

例:&& でコマンド組み合わせる
ls *.jpg && mv *.jpg /Users/takuya/Pictures 
例:&& とtestの組み合わせ。
# ファイルが有れば中身を表示する
test -e /etc/passwd && cat /etc/passwd

|| でコマンドをOR実行する

OR でコマンドを実行することが出来ます。使い方は次のとおりです。

COMMAND3 || COMMAND4

読み方としては、COMMAND3 を実行し、成功したら次の行へ、失敗したらCOMMAND4を実行して次の行へ。という意味です。

繰り返しになりますが、ここで AND / OR と呼んでいるのは「終了ステータス」のAND・ORです。

ファイルなければ作る
test -e my-sample.txt || touch my-sample.txt

|| 失敗したら処理をやめる

|| を使えば「失敗したら処理をやめる」ということ出来ます

takuya ユーザーがいなければexitして処理をやめる
id takuya || exit 

まとめ

if の条件を考えるまえに、以下のことを覚えておくと、スッキリします。迷わずに住みます。

終了ステータスで判断するので、かんたんな条件ならif 無しで書くことが出来ます。また、そのほうがわかりやすいこともあります。

コマンドの終了ステータスコードで「判断する」は大事なので絶対覚えておいてください。

大事なので10回位書きました。

もちろん if を書いたほうが読みやすいので、if を使うほうが良いのでしょうが、if をいきなり使ってしまうと「何を以てTRUEか」という事を見逃しがちです。 &&||で分岐は出来ます。敢えて if を使わないで十分な条件分岐が出来ることを紹介しました。

おまけ

if 文を使わずとも、かんたんな条件分岐なら、 &&{ } を使って書くことが出来ます。

test -e /etc/passwd && { echo /etc/passwd は存在しました; echo ファイルの末尾を表示します; tail /etc/passwd ;}

さらにこれは、{ } 内部で改行が許されるので、次のようにかけます。

test -e /etc/passwd && {
   echo /etc/passwd は存在しました;
   echo ファイルの末尾を表示します;
   tail /etc/passwd ;
}

次の bash の条件分岐 if の記事では、この改行を含めたコードを、 「プログラミング」っぽく if を使うようにしておきたいと思います。

おまけ

この記事で紹介した終了ステータスを使ってANDでみることは、bashrcなどで盛んに行われます。

例:takuyaのbashrc からの抜粋
[ -z "$PS1" ] && return
[ -f ~/.bash_aliases ] && source ~/.bash_aliases
(( $BASH_VERSINFO >= 4 )) && shopt -s globstar

コピペして肥大化したbashrcをよく見るといたるところで使われていると感じると思います。

参考資料