Bashのcase文の書き方: パターンで分岐処理

25, 2020-08-23

目次

Bashのcase文の書き方

Bashにはcase文があります。
これはCやJavaScriptで言うところのswitch文に近いものです。

これを使うと、if文を使うより分岐処理が簡単に書ける場合があります。

case 1 in
    0 ) echo "match 0" ;;
    1 ) echo "match 1" ;;
    2 ) echo "match 2" ;;
esac
# match 1

case文の構造

case文は↓のような構造を持っています。

case 値 in
    パターン1 ) 処理 ;;
    パターン2 ) 処理 ;;
    ...
    パターンn ) 処理 ;;
esca

caseに値を渡し、その値に応じて処理が分岐します。
値にマッチしたパターンの処理が実行され、他の分岐の処理は実行されません。

整数による分岐

caseに整数を渡し、パターンに整数を列挙すると、パターンにマッチした処理が呼ばれます。
↓の場合、caseで評価している値は1なので、1 )のケースにマッチします。

case 1 in
    0 ) echo "match 0" ;;
    1 ) echo "match 1" ;;
    2 ) echo "match 2" ;;
esac
# match 1

caseに渡す値は変数にすることも出来ます。

num=1

case "$num" in
    0 ) echo "match 0" ;;
    1 ) echo "match 1" ;;
    2 ) echo "match 2" ;;
esac
# match 1

defaultパターン

先ほどの整数のcase文ですが、値が0~2のいずれかでなければ、どの分岐の処理も実行されません。
いずれの分岐にもマッチしない場合の処理を書きたい場合は、パターンにアスタリスク(*)を使います。

num=3

case "$num" in  # <- numには3が入っている
    0 ) echo "match 0" ;;
    1 ) echo "match 1" ;;
    2 ) echo "match 2" ;;
    * ) echo "match *" ;;  # <- これが実行される
esac
# match *

文字列による分岐

caseには文字列を指定することも出来ます。
$1はスクリプトの第1引数です)

case "$1" in
    "cat" ) echo "match cat" ;;
    "dog" ) echo "match dog" ;;
    "bird" ) echo "match bird" ;;
    * ) echo "match *" ;;
esac

実行結果。

$ bash sample.sh cat
match cat

$ bash sample.sh dog
match dog

$ bash sample.sh bird
match bird

$ bash sample.sh pig
match *

パターンにORを使う

caseのパターンはOR(|)で繋ぐことが出来ます。
Aのパターン、またはBのパターンのどちらかにマッチさせたい分岐を書く場合に使います。

case "$1" in
    "cat" | "Cat" ) echo "match cat|Cat" ;;
    "dog" | "Dog" ) echo "match dog|Dog" ;;
    "bird" | "Bird" ) echo "match bird|Bird" ;;
    * ) echo "match *" ;;
esac

実行結果。

$ bash sample.sh cat
match cat|Cat

$ bash sample.sh Cat
match cat|Cat

$ bash sample.sh dog
match dog|Dog

$ bash sample.sh Dog
match dog|Dog

$ bash sample.sh bird
match bird|Bird

$ bash sample.sh Bird
match bird|Bird

$ bash sample.sh pig
match *

ワイルドカードによるマッチ

Bashのcase文のパターンにはワイルドカード(*)を使うことが出来ます。
*は任意の文字列(空文字を含む)を意味します。

case "$1" in
    # 先頭文字が'c'で始まり、任意の文字が続く文字列にマッチする
    c* ) echo "match c*" ;;

    # 先頭文字が'd'で始まり、任意の文字が続く文字列にマッチする
    d* ) echo "match d*" ;;

    # 先頭文字が'b'で始まり、任意の文字が続く文字列にマッチする
    b* ) echo "match b*" ;;

    # 全てにマッチする
    * ) echo "match *" ;;
esac

実行結果。

$ bash sample.sh cat
match c*

$ bash sample.sh dog
match d*

$ bash sample.sh bird
match b*

$ bash sample.sh pig
match *

任意の1文字へのマッチ

パターンに?を使うと任意の1文字にマッチさせることができます。

case "$1" in
    # 先頭文字が任意で、2文字目が'a'の文字列にマッチする
    ?a* ) echo "match ?a*" ;;

    # 先頭文字が任意で、2文字目が'o'の文字列にマッチする
    ?o* ) echo "match ?o*" ;;

    # 先頭文字が任意で、2文字目が'i'の文字列にマッチする
    ?i* ) echo "match ?i*" ;;

    * ) echo "match *" ;;
esac

実行結果。

$ bash sample.sh cat
match ?a*

$ bash sample.sh dog
match ?o*

$ bash sample.sh bird
match ?i*

$ bash sample.sh pig
match ?i*

グループによるマッチ

パターンに[]を使うと、マッチさせる文字をグループ化することが出来ます。

case "$1" in
    # 先頭文字にa, b, cのいずれかの文字を含む文字列にマッチする
    [abc]* ) echo "match [abc]*" ;;

    # A~Zまたはa~zのいずれかの先頭文字を含む文字列にマッチする
    # 正規表現とは違い小文字と大文字を区別しないので注意
    [A-Z]* ) echo "match [A-Z]*" ;;

    # "!"はカッコの中のいずれでもないという意味
    # よってa, b, cのいずれでもない文字にマッチする
    [!abc]* ) echo "match [!abc]*" ;;
    * ) echo "match *" ;;
esac

実行結果。

$ bash sample.sh cat
match [abc]*

$ bash sample.sh dog
match [A-Z]*

$ bash sample.sh bird
match [abc]*

$ bash sample.sh pig
match [A-Z]*

$ bash sample.sh 123
match [!A-Z]

パターンに変数を使用する

パターンは変数に保存することも出来ます。

name="cat"

pat_1="cat"
pat_2="dog"
pat_3="bird"

case "$name" in  # <- nameには"cat"が入っている
    "$pat_1" ) echo "match $pat_1" ;;  # <- これにマッチする
    "$pat_2" ) echo "match $pat_2" ;;
    "$pat_3" ) echo "match $pat_3" ;;
    * ) echo "match *"
esac
# match cat

ワイルドカードやグループを使う場合

ワイルドカードやグループを変数に書くことも出来ますが、それらを使う場合は変数をダブルクオートで囲まないようにします。
ダブルクオートで囲むと文字列として認識されます。

pat_1="c*"
pat_2="[dD]og"
pat_3="[bB]ird"

case "$1" in
    $pat_1 ) echo "match $pat_1" ;;
    $pat_2 ) echo "match $pat_2" ;;
    $pat_3 ) echo "match $pat_3" ;;
    * ) echo "match *"
esac

実行結果。

$ bash sample.sh cat
match c*

$ bash sample.sh Dog
match [dD]og

$ bash sample.sh bird
match [bB]ird

使用例

Bashのcase文の使用例です。

メールアドレスのドメインごとに分岐する

メールアドレスのドメインごとに処理を分岐します。

case "$1" in
    *@gmail.com ) echo "You are gmail user" ;;
    *@docomo.co.jp ) echo "You are docomo user" ;;
    *@ez.web.jp ) echo "You are AU user" ;;
    * ) echo "Unknown" ;;
esac

実行結果。

$ bash a.sh ababa@gmail.com
You are gmail user

$ bash a.sh ababa@docomo.co.jp
You are docomo user

$ bash a.sh ababa@ez.web.jp
You are AU user

$ bash a.sh ababa@infoseek.jp
Unknown

終了確認プロンプト

「本当に終了しますか?」というプロンプトを出して入力に応じて処理を分岐します。

while true; do
    echo "本当に終了しますか?(y/n)"
    read line

    case "$line" in
        [yY]es | [yY] ) break ;;
        [nN]o | [nN] ) echo "続行します。" ;;
        * ) echo "不正な入力です。" ;;
    esac
done

実行結果。

$ bash sample.sh
本当に終了しますか?(y/n)
n
続行します。
本当に終了しますか?(y/n)
No
続行します。
本当に終了しますか?(y/n)
ababa
不正な入力です。
本当に終了しますか?(y/n)
Yes

問題

Q1: case文のパターンに使えるデータを答えよ

  1. 数値

  2. 文字列

  3. パターン

Q2: case文のパターンで変数を使う場合の注意事項を答えよ

  1. ワイルドカードやグループを使う場合は変数をバッククオートで囲ってはならない

  2. ワイルドカードやグループを使う場合は変数をダブルクオートで囲ってはならない

  3. ワイルドカードやグループを使う場合は変数をダブルクオートで囲む

Q3: case文のパターンで「先頭にa, b, cのいずれかを含む文字列」として適当なパターンを答えよ

  1. [!abc]*

  2. [abc]*

  3. [0-9]*


正解

Q1: 1, 2, 3
Q2: 2
Q3: 2



この記事のアンケートを送信する