はじめに#
シェルスクリプトで「この値だったらこうする、あの値だったらああする」って複数の条件分岐を書くとき、if文をずらずら並べてると読みづらくなりますよね。そんなときに便利なのがcaseコマンドです。
caseは複数の値やパターンに対する処理を、見やすく簡潔に書けるシェルスクリプトの制御構文。メニュー選択やオプション解析、ファイルの種類判定など、いろんな場面で大活躍します。
caseとは#
caseはシェルの組み込みコマンドで、変数の値がどのパターンにマッチするかを判定して、対応する処理を実行します。他のプログラミング言語でいうswitch文みたいなやつですね。
特徴は以下の通り:
- ワイルドカード(
*、?、[]など)が使える
- 複数のパターンを
|で並べられる
if-elif-elseより読みやすい
- パターンマッチングが強力
基本構文#
1
2
3
4
5
6
7
8
9
10
11
|
case 変数 in
パターン1)
コマンド1
;;
パターン2)
コマンド2
;;
*)
デフォルトのコマンド
;;
esac
|
構文のポイント:
case 変数 inで始まり、esacで終わる(caseの逆綴り)
- 各パターンは
)で終わる
- 各ケースの終わりは
;;で区切る
*は「それ以外全部」(デフォルトケース)
- パターンにはワイルドカードが使える
主なパターン記法#
| パターン |
説明 |
例 |
文字列 |
完全一致 |
yes、no |
* |
任意の文字列 |
デフォルトケース |
? |
任意の1文字 |
a?b(axb、aybなど) |
[...] |
文字クラス |
[0-9]、[a-z] |
パターン1|パターン2 |
複数パターン(OR) |
y|yes|Y|YES |
[!...] |
否定文字クラス |
[!0-9](数字以外) |
使用例#
1. 基本的な使い方#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!/bin/bash
read -p "続けますか? (yes/no): " answer
case $answer in
yes)
echo "続行します"
;;
no)
echo "終了します"
;;
*)
echo "yes か no で答えてください"
;;
esac
|
シンプルな条件分岐。ifだとif [ "$answer" = "yes" ]って書くところが、caseだとすっきり書けます。
2. 複数パターンのマッチング#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!/bin/bash
read -p "続けますか? (y/n): " answer
case $answer in
y|yes|Y|YES)
echo "続行します"
;;
n|no|N|NO)
echo "終了します"
;;
*)
echo "無効な入力です"
;;
esac
|
|を使って複数のパターンをまとめて処理。大文字小文字どっちでも反応するようにできます。
3. ワイルドカードを使ったパターン#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/bin/bash
filename="test.txt"
case $filename in
*.txt)
echo "テキストファイルです"
;;
*.jpg|*.png|*.gif)
echo "画像ファイルです"
;;
*.sh)
echo "シェルスクリプトです"
;;
*)
echo "不明なファイル形式です"
;;
esac
|
ファイルの拡張子で処理を分けるときに便利。*で「何でもいい文字列」を表現できます。
4. 数値の範囲判定#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/bin/bash
read -p "1〜10の数字を入力: " num
case $num in
[1-3])
echo "小さい数字です"
;;
[4-7])
echo "中くらいの数字です"
;;
[8-9]|10)
echo "大きい数字です"
;;
*)
echo "範囲外の値です"
;;
esac
|
[1-3]みたいに範囲指定ができます。ただし、1桁の数字にしか使えないので注意。
5. メニューシステム#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#!/bin/bash
echo "=== メニュー ==="
echo "1. ファイル一覧"
echo "2. ディレクトリ作成"
echo "3. 終了"
read -p "選択してください: " choice
case $choice in
1)
echo "ファイル一覧:"
ls -l
;;
2)
read -p "ディレクトリ名: " dirname
mkdir "$dirname"
echo "$dirname を作成しました"
;;
3)
echo "終了します"
exit 0
;;
*)
echo "無効な選択です"
;;
esac
|
メニュー形式のスクリプトでよく使うパターン。数字で選択肢を選ばせるときに読みやすいです。
6. コマンドライン引数の解析#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#!/bin/bash
case $1 in
start)
echo "サービスを開始します"
;;
stop)
echo "サービスを停止します"
;;
restart)
echo "サービスを再起動します"
;;
status)
echo "サービスの状態を確認します"
;;
*)
echo "使い方: $0 {start|stop|restart|status}"
exit 1
;;
esac
|
引数で動作を切り替えるスクリプトの典型的なパターン。systemctlみたいなコマンドの作り方ですね。
7. 日付や曜日による処理#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/bin/bash
day=$(date +%A)
case $day in
Monday)
echo "月曜日です。今週も頑張りましょう!"
;;
Friday)
echo "金曜日です。もうすぐ週末!"
;;
Saturday|Sunday)
echo "週末です。ゆっくり休んでください"
;;
*)
echo "平日です。お疲れ様です"
;;
esac
|
曜日によって処理を変えるスクリプト。cronで定期実行するときとかに使えます。
8. 環境変数による設定切り替え#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#!/bin/bash
case $ENVIRONMENT in
dev|development)
echo "開発環境で実行します"
DEBUG=true
;;
stg|staging)
echo "ステージング環境で実行します"
DEBUG=false
;;
prod|production)
echo "本番環境で実行します"
DEBUG=false
;;
*)
echo "環境が指定されていません"
exit 1
;;
esac
|
環境変数で動作を切り替える。複数の環境名を受け付けられるのが便利。
9. ファイルの種類判定(詳細版)#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#!/bin/bash
file="document.pdf"
case $file in
*.tar.gz|*.tgz)
echo "圧縮されたアーカイブファイル"
;;
*.zip|*.rar|*.7z)
echo "圧縮ファイル"
;;
*.jpg|*.jpeg|*.png|*.gif|*.bmp)
echo "画像ファイル"
;;
*.mp4|*.avi|*.mov|*.mkv)
echo "動画ファイル"
;;
*.pdf)
echo "PDFドキュメント"
;;
*.doc|*.docx|*.txt)
echo "文書ファイル"
;;
*)
echo "不明なファイル形式"
;;
esac
|
より実践的なファイル判定。拡張子が二重になってるやつ(.tar.gz)もちゃんと判定できます。
10. ユーザー入力の検証#
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/bash
read -p "メールアドレスを入力: " email
case $email in
*@*.*)
echo "有効なメールアドレス形式です"
;;
*)
echo "メールアドレスの形式が正しくありません"
;;
esac
|
簡易的なメールアドレスの検証。完璧じゃないけど、基本的なチェックには使えます。
11. 複数条件の組み合わせ#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/bin/bash
read -p "ファイル名を入力: " filename
case $filename in
[Tt]est*.txt)
echo "testで始まるテキストファイル"
;;
[0-9]*.log)
echo "数字で始まるログファイル"
;;
backup_[0-9][0-9][0-9][0-9]*.tar.gz)
echo "バックアップアーカイブ(年付き)"
;;
*)
echo "その他のファイル"
;;
esac
|
文字クラスとワイルドカードを組み合わせた複雑なパターン。命名規則に沿ったファイルを見分けられます。
12. オプションフラグの解析#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#!/bin/bash
while [ $# -gt 0 ]; do
case $1 in
-h|--help)
echo "使い方: $0 [options]"
echo " -h, --help ヘルプを表示"
echo " -v, --version バージョンを表示"
echo " -d, --debug デバッグモード"
exit 0
;;
-v|--version)
echo "バージョン 1.0.0"
exit 0
;;
-d|--debug)
echo "デバッグモードを有効化"
DEBUG=true
shift
;;
-*)
echo "不明なオプション: $1"
exit 1
;;
*)
break
;;
esac
done
|
コマンドラインオプションを解析する実践的な例。-hと--helpの両方を受け付けられます。
Tips・注意点#
パターンマッチの順序#
caseは上から順番に評価されて、最初にマッチしたパターンだけが実行されます。広いパターン(*など)は最後に書きましょう。
1
2
3
4
5
6
7
8
|
case $value in
*) # これを最初に書くと...
echo "全部ここにマッチしちゃう"
;;
specific)
echo "ここには絶対来ない"
;;
esac
|
クォートは不要#
パターンマッチング部分では変数にクォートを付けなくてOKです。というか付けると逆にマッチしません。
1
2
3
4
5
6
7
8
9
|
# OK
case $var in
pattern) echo "マッチ" ;;
esac
# NG - パターンとして認識されない
case "$var" in
"pattern") echo "これはダメ" ;;
esac
|
;;と;;&の違い#
通常は;;を使いますが、他にも終端記号があります:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
case $value in
a)
echo "aにマッチ"
;; # ここで終了(通常)
b)
echo "bにマッチ"
;& # 次のケースも必ず実行
c)
echo "cにマッチ(or bの次)"
;;& # 次のパターンマッチも試す
*)
echo "その他"
;;
esac
|
でも実際;;しか使わないことがほとんどです。
数値の範囲判定の限界#
[1-9]は1桁の数字しか判定できません。10以上の数値には使えないので注意。
1
2
3
4
5
6
|
# これは期待通りに動かない
case $num in
[10-20]) # 1, 0, -, 2 のいずれか1文字にマッチ
echo "10から20の範囲"
;;
esac
|
複雑な数値範囲判定はif文を使った方がいいです。
正規表現は使えない#
caseはワイルドカードパターンであって、正規表現じゃありません。.*とか[0-9]+みたいな正規表現は使えないので注意。
1
2
3
4
5
6
|
# これは正規表現じゃなくてワイルドカード
case $var in
[0-9]*) # 数字で始まる任意の文字列
echo "数字始まり"
;;
esac
|
実践的な使い方#
インタラクティブなメニューシステム#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#!/bin/bash
show_menu() {
echo "================================"
echo " システム管理メニュー"
echo "================================"
echo "1. ディスク使用状況"
echo "2. メモリ使用状況"
echo "3. 実行中のプロセス"
echo "4. ネットワーク情報"
echo "5. 終了"
echo "================================"
}
while true; do
show_menu
read -p "選択してください (1-5): " choice
case $choice in
1)
echo -e "\n=== ディスク使用状況 ==="
df -h
;;
2)
echo -e "\n=== メモリ使用状況 ==="
free -h
;;
3)
echo -e "\n=== 実行中のプロセス ==="
ps aux | head -10
;;
4)
echo -e "\n=== ネットワーク情報 ==="
ip addr show
;;
5)
echo "終了します"
exit 0
;;
*)
echo "エラー: 1-5 の数字を入力してください"
;;
esac
echo ""
read -p "Enterキーで続行..."
done
|
ループと組み合わせて本格的なメニューシステムを作れます。システム管理のツールとかでよく見るやつですね。
ファイル処理の振り分け#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#!/bin/bash
process_file() {
local file=$1
case $file in
*.jpg|*.jpeg|*.png|*.gif)
echo "画像を圧縮: $file"
# convert "$file" -quality 85 "compressed_$file"
;;
*.mp4|*.avi|*.mov)
echo "動画を変換: $file"
# ffmpeg -i "$file" -c:v libx264 "converted_$file"
;;
*.txt|*.log)
echo "テキストをアーカイブ: $file"
# gzip "$file"
;;
*.tar.gz|*.zip)
echo "アーカイブを展開: $file"
# tar -xzf "$file" 2>/dev/null || unzip "$file"
;;
*)
echo "スキップ: $file(未対応の形式)"
;;
esac
}
# すべての引数を処理
for file in "$@"; do
process_file "$file"
done
|
複数のファイルを自動的に判別して処理。バッチ処理のスクリプトで重宝します。
環境別のデプロイスクリプト#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#!/bin/bash
ENVIRONMENT=${1:-dev}
case $ENVIRONMENT in
dev|development)
echo "開発環境にデプロイします"
SERVER="dev.example.com"
PORT=3000
DEBUG=true
;;
stg|staging)
echo "ステージング環境にデプロイします"
SERVER="stg.example.com"
PORT=80
DEBUG=false
;;
prod|production)
read -p "本番環境にデプロイしますか? (yes/no): " confirm
case $confirm in
yes)
echo "本番環境にデプロイします"
SERVER="prod.example.com"
PORT=80
DEBUG=false
;;
*)
echo "デプロイを中止しました"
exit 0
;;
esac
;;
*)
echo "エラー: 不明な環境 '$ENVIRONMENT'"
echo "使い方: $0 {dev|stg|prod}"
exit 1
;;
esac
echo "サーバー: $SERVER"
echo "ポート: $PORT"
echo "デバッグ: $DEBUG"
# デプロイ処理をここに書く
|
caseをネストして使うこともできます。環境ごとに設定を変えるデプロイスクリプトの定番パターン。
まとめ#
caseコマンドのポイント:
- 複数の値やパターンに対する分岐処理を簡潔に書ける
- ワイルドカード(
*、?、[])でパターンマッチング
|で複数パターンをまとめられる
- メニューシステムやオプション解析で大活躍
if-elif-elseより読みやすく保守しやすい
if文をずらずら並べるより、caseを使った方がコードが読みやすくなります。特にメニュー選択やファイル種別判定、コマンド引数の解析なんかでは必須のテクニックです。
複数の条件分岐が必要になったら、まずcaseを検討してみましょう!