条件

条件分岐 の Bash

{other: "%{count}個の演習"}

条件分岐について

Bashにおける真偽

Bashには真偽値という概念がありません。 あるのは文字列と数値、そして文字列や数値の配列です。 では、条件を扱うコマンドは、どのようにして真と偽を判断するのでしょうか。

終了ステータス

コマンドは終了するときに_終了ステータス_を返します。 終了ステータスは0以上255以下の整数です。 Bashはゼロの終了ステータスを_成功_とみなします。 それ以外の終了ステータスは_失敗_を表します。

これは、bashの組み込みコマンド、キーワード、関数を含む、すべてのコマンドに当てはまります。

ifコマンド

ifコマンドの基本的な構文は次のとおりです。

if CONDITIONAL_COMMANDS; then TRUE_COMMANDS; else FALSE_COMMANDS; fi

ifで始まり、条件のコマンドと「成功」時のコマンドはthenで区切られ、fiで終わります。 else節は省略できます。

CONDITIONAL_COMMANDSは、単一のコマンドでも、コマンドのリストでもかまいません。

CONDITIONAL_COMMANDSが実行され、次のようになります。

  • 終了ステータスがゼロ(成功)なら、TRUE_COMMANDSが実行されます。
  • 終了ステータスが非ゼロ(失敗)なら、FALSE_COMMANDSがあれば実行されます。

elifを使うと、分岐を連ねることができます。

if CONDITIONAL_COMMANDS
then TRUE_COMMANDS
elif CONDITIONAL_COMMANDS_2
then TRUE_COMMANDS_2
# more elif branches ...
else FALSE_COMMANDS
fi

then、elif、else、fiの前には、セミコロンか改行が必要です。

強調しておくと、流れを制御するのは条件コマンドの終了ステータスです。 たとえば、grepは一致が見つかれば0を、見つからなければ1を返します。 -qオプションは出力を抑え、終了ステータスだけを返します。

if grep -q "my pattern" my_file; then echo "the pattern is found in the file"; fi

[とtestコマンド

CONDITIONAL_COMMANDSの周りに特別な構文はありません。 次のようなif文に見覚えがあるかもしれません。

if [ "$password" = "secure" ]; then
    echo "Welcome!"
fi

[は特別な構文ではありません。 条件式を評価し、成功か失敗のステータスで終了する_コマンド_です。 すべてのコマンドと同様に、これと引数の間には空白が必要です。

[は実際にはtestコマンドの別名です。 まったく同じものですが、[の最後の引数は]で_なければなりません_。

条件式

[と]の間には、条件式を書きます。 よくある条件式には、次のようなものがあります。

[ -f "$filename" ]             # file operations
[ "$string1" = "$string2" ]    # string comparisons
[ "$num1" -eq "$num2" ]        # arithmetic comparisons

利用できる演算はもっとたくさんあり、マニュアルのBashの条件式の節に一覧があります。

Note

上の例では、すべての変数が引用符で囲まれていることに注目してください。 testと[は普通のコマンドで、引数は他のコマンドと同じように単語分割とファイル名展開の対象になります。

これが重要なのは、条件式が、与える_引数の数_によって異なる評価を受けるからです。

  • 引数が0個:終了ステータスは非ゼロ(失敗)
  • 引数が1個:引数が空でなければ終了ステータスはゼロ(成功)、空なら非ゼロ。
  • 引数が2個:最初の引数は単項演算子([ -z "$name" ]など)か、!(引数1個のテストのステータスを反転させる)でなければなりません。
  • さらに詳しくはこちら。

引用符を忘れると、予期しない結果になることがあります。

str=""

# this prints "empty"
if [ -n "$str" ]; then echo "not empty"; else echo "empty"; fi

# leaving the variable unquoted results in incorrect "not empty" output
if [ -n $str ]; then echo "not empty"; else echo "empty"; fi

[[キーワード

[[...]]という条件構文は_コマンド_ではなく、キーワードです。 つまり、他のコマンドと同じように扱われますが、特別な構文解析のルールがあります。 [[の特別な点は、その中で展開される変数が、単語分割やファイル名展開の対象にならないことです。 そのため、このコマンドは引用符を付けなくても、期待どおりに動作します。

if [[ -n $str ]]; then echo "not empty"; else echo "empty"; fi

[[は、testと[が扱えるすべての条件式をサポートします。 さらに、[[には次のものがあります。

  • =~という正規表現マッチングの演算子
  • ==と!=がグロブパターンのマッチング演算子として働く
  • &&と||が論理演算子として働く(特別な構文解析ルール)
  • <と>が「そのままの」文字列比較演算子として働く(特別な構文解析ルール:これらはリダイレクト記号なので、[ではエスケープしなければなりません)

これらの特別な機能は非常に便利なので、[[だけを使うべきだという考えが広く支持されています。 (たとえば、Google Shell Style Guideを参照してください。)

caseコマンド

caseも制御フローのコマンドです。 他の言語の「switch」文のようなものです。

case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac

WORDは、それぞれのPATTERNと照合されます。 どれかが一致すると、そのCOMMANDSが実行されます。

read -p "Guess the secret word: " word
case "$word" in
    secret) echo "Yes, you guessed it!" ;;
    ??????) echo "That's the right number of letters." ;;
    s*)     echo "You guessed the first letter." ;;
    *)      echo "Not even close! Try again." ;;
esac

各COMMANDS節は、2つのセミコロン;;で終わらなければなりません。

Note
  1. フォールスルーでコマンドを実行したり、パターンマッチングを続けたりする機能を提供する代替手段があります。 詳しくはマニュアルを確認してください。
  2. パターンについては、引用の概念のファイル名展開の節で説明したことを思い出してください。
GitHubで編集 リンクは新しいウィンドウまたはタブで開きます