case
『case』文は変数やコマンドの出力をパターンと照合して処理を分岐します。複数の値への多分岐をシンプルに書けるため、コマンドライン引数の処理やメニュー選択などでよく使います。
構文
case 変数 in
パターン1)
処理1
;;
パターン2 | パターン3)
処理2
;;
*)
デフォルト処理
;;
esac
パターン一覧
| パターン | 概要 |
|---|---|
| word) | 完全一致です。word と等しいときに実行されます。 |
| pat1 | pat2) | OR 条件です。どちらかに一致すれば実行されます。 |
| *.txt) | ワイルドカードパターンです。.txt で終わる文字列に一致します。 |
| [aeiou]) | 文字クラスです。a・e・i・o・u のいずれかに一致します。 |
| ?) | 任意の1文字に一致します。『??)』なら2文字、『???)』なら3文字に一致します。文字数が固定の場合に使います。 |
| [0-9]) | 範囲指定の文字クラスです。0〜9 のいずれか1文字に一致します。 |
| [!a-z]) | 否定の文字クラスです。a〜z 以外の1文字に一致します。 |
| *) | すべてに一致するデフォルトパターンです。最後に置きます。 |
| ;; | パターンブロックの終端です(次のパターンに落ちません)。 |
| ;& | 次のパターンブロックにも続けて実行します(Bash 4以降)。 |
| ;;& | 次のパターンを評価して一致すれば実行します(Bash 4以降)。 |
サンプルコード
コマンドライン引数に応じて処理を分岐します。『|』でOR条件をまとめられます。
sample_service.sh
#!/bin/bash
action=$1
case "$action" in
start)
echo "サービスを起動します"
;;
stop)
echo "サービスを停止します"
;;
restart | reload)
echo "サービスを再起動します"
;;
status)
echo "サービスの状態を確認します"
;;
*)
echo "使い方: $0 {start|stop|restart|reload|status}"
exit 1
;;
esac
実行するコマンドは次の通りです。
bash service.sh restart サービスを再起動します
ワイルドカードパターンでファイルの種類を判定します。
sample_filetype.sh
filename="report.pdf"
case "$filename" in
*.php | *.py | *.rb)
echo "スクリプトファイルです"
;;
*.txt | *.md | *.csv)
echo "テキストファイルです"
;;
*.jpg | *.png | *.gif)
echo "画像ファイルです"
;;
*.pdf)
echo "PDF ファイルです"
;;
*)
echo "不明なファイル形式です"
;;
esac
実行するコマンドは次の通りです。
bash filetype.sh PDF ファイルです
文字クラス『[0-9]』を使って数値の範囲を判定します。
sample_grade_case.sh
score=85
case $score in
9[0-9] | 100)
echo "A(優)"
;;
8[0-9])
echo "B(良)"
;;
7[0-9])
echo "C(可)"
;;
*)
echo "D(不可)"
;;
esac
実行するコマンドは次の通りです。
bash grade_case.sh B(良)
『?』は任意の1文字に一致するワイルドカードです。文字数を固定したい場合に使います。例えば『???)』なら3文字、『?????)』なら5文字に一致します。郵便番号や日本のナンバー、固定長コードの判定に便利です。
sample_zip_check.sh
zip=$1
case "$zip" in
???-????)
echo "日本の郵便番号形式です(3桁-4桁)"
;;
?????)
echo "5桁の数字(旧形式またはアメリカのZIP)"
;;
?)
echo "1文字だけ入力されました"
;;
"")
echo "空文字列です"
;;
*)
echo "認識できない形式です"
;;
esac
実行するコマンドは次の通りです。
bash zip_check.sh 100-0001 日本の郵便番号形式です(3桁-4桁) bash zip_check.sh 12345 5桁の数字(旧形式またはアメリカのZIP) bash zip_check.sh A 1文字だけ入力されました
『?』は1文字「以上」ではなく「ちょうど1文字」を意味する点に注意します。例えば『??)』は2文字に一致しますが、1文字や3文字には一致しません。任意の文字数に一致させたい場合は『*』を使います。
よくあるミス
よくあるミス1: ;; を忘れてしまう
各パターンブロックの末尾に『;;』がないと、次のパターンの処理が続けて実行されてしまいます。
service_ng.sh
#!/bin/bash
action=$1
case "$action" in
start)
echo "サービスを起動します"
# ;; を書き忘れている
stop)
echo "サービスを停止します"
;;
esac
修正後は次の通りです。
bash service_ng.sh start サービスを起動します サービスを停止します
『;;』を各ブロックの末尾に付けることで、意図したブロックだけが実行されます。
service_ok.sh
#!/bin/bash
action=$1
case "$action" in
start)
echo "サービスを起動します"
;;
stop)
echo "サービスを停止します"
;;
esac
修正後は次の通りです。
bash service_ok.sh start サービスを起動します
よくあるミス2: 変数をクォートせずに渡す
case の値にクォートなしの変数を使うと、変数が空のときや空白を含むときに予期しない動作になる場合があります。
case_unquoted_ng.sh
#!/bin/bash
action=""
case $action in
start)
echo "起動"
;;
*)
echo "不明"
;;
esac
修正後は次の通りです。
bash case_unquoted_ng.sh 不明
変数をダブルクォートで囲むことで、空文字列や空白を含む値も安全に扱えます。
case_quoted_ok.sh
#!/bin/bash
action=""
case "$action" in
start)
echo "起動"
;;
"")
echo "値が空です"
;;
*)
echo "不明"
;;
esac
修正後は次の通りです。
bash case_quoted_ok.sh 値が空です
概要
case のパターンはシェルのグロブパターン(ワイルドカード)であり、正規表現ではありません。正規表現マッチが必要な場合は if / [[ ]] の =~ 演算子 を使います。
パターンを『|』で区切ることで OR 条件を1つのブロックにまとめられます。これを if-elif と比較すると、case の方がすっきり書けて可読性が上がります。
『*)』のデフォルトパターンは省略可能ですが、想定外の入力への対処として書いておくと安全です。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。