シェルスクリプトに挑戦しよう(9)制御構文[その2]――caseによる条件分岐“応用力”をつけるためのLinux再入門(29)

今回は、文字列のパターンで分岐する「case」を解説します。複数の条件で“Aなら~する”、“Bなら~する”、“Cなら~する”のように処理を分けたい場合は、「if ~ elif ~ elif ~……」で書くこともできますが、文字列のパターンで分岐する場合は「case」が便利です。

» 2018年11月21日 05時00分 公開
[西村めぐみ@IT]
「“応用力”をつけるためのLinux再入門」のインデックス

“応用力”をつけるためのLinux再入門

caseの基礎構文

 case文は以下のように書きます。「case」で始まり、「case」を逆から書いた「esac」で終わります。

  1. case 文字列 in
  2. パターン1) 文字列がパターン1に該当したときのコマンド ;;
  3. パターン2) 文字列がパターン2に該当したときのコマンド ;;
  4. *) 文字列がどのパターンにも該当しなかったときのコマンド ;;
  5. esac
▲case文の書き方

 分岐は「パターン) パターンに合致した場合の処理」のように書きます。パターンには「*」や「?」などの記号を使うことができます。

 パターンに合っているかどうかは、上から順番にチェックされます。1つ目のパターンに一致していれば、それ以降は処理されません。従って、最後に「*)」というパターンを置くことで、“全てに該当しなかった場合”という処理を書くことができます。

 「;;」は、「パターン) 処理」という組み合わせのリストの“区切り”を意味しています。従って、最後の「;;」は省略可能です。

 なお、「in」「)」「;;」の前後の改行は自由です。複数のコマンドを実行したい場合は、改行または「;」で区切ります。

caseを試してみる

 今回は「引数の内容に応じて処理を変える」という動作を試してみましょう。シェルスクリプトの中でキー入力を受け取る方法については、次回解説します。

 例えば、1つ目の引数が「y」なら「echo "YES"」と「echo "OK"」の2つを実行し、「n」なら「echo "NO"」を実行、それ以外なら「echo "undefined"」を実行するとしてみましょう。次のようになります。

 なお、文字列である「"y"」と「"n"」の引用符(")は省略可能です。最後の「*」はパターンとして指定しているので、引用符を付けない点に注意してください。

  1. #! /bin/bash
  2. case "$1" in
  3. "y")
  4. echo "YES"
  5. echo "OK"
  6. ;;
  7. "n")
  8. echo "NO"
  9. ;;
  10. *)
  11. echo "undefined";;
  12. esac
  13. 不明
▲YES、NOを表示するcase文(showyesno)
  1. $ chomod +x showyesno
  2. $ ./showyesno y
  3. YES
  4. OK
  5. #(引数が「y」だったので「YES」と「OK」が表示された)
  6. $ ./showyesno n
  7. NO
  8. #(引数が「n」だったので「NO」が表示された)
  9. $ ./showyesno aaa
  10. undefined
  11. #(引数が「y」でも「n」でもないので「undefined」が表示された)
▲実行結果(showyesno)

●case文の改行ルール

 先ほどの例(showyesno)では、「in」「)」「;;」で改行していますが、ここの改行は自由です。例えば、それぞれのパターンを1行にするのであれば、以下のようになります。

 「"y")」のパターンでは実行するコマンドが2つあるので、「;」で区切っています。なお、最後の「;;」は省略可能です。

  1. #! /bin/bash
  2. case "$1" in
  3. "y") echo "YES"; echo "OK";;
  4. "n") echo "NO";;
  5. *) echo "undefined";;
  6. esac
▲各パターンを1行にまとめてコンパクトにした場合(showyesnoを加工)

 さらに短く、1行に全てをまとめることもできます。この場合、esac直前の「;;」は省略できません。

  1. #! /bin/bash
  2. case "$1" in "y") echo "YES"; echo "OK";; "n") echo "NO";; *) echo "undefined";; esac
▲全てを1行にした場合(showyesnoを加工)

 case文全てを1行にするのはやや極端ですが、それぞれの処理が短く、内容が決まっているならば、ある程度まとめた方が読みやすくなるかもしれません。

 一方、これからコマンドを追加する、パターンを複雑にするなど、スクリプトの編集を考えている場合は、最初の書き方のように、パターンや各コマンドが独立した行になっている方が扱いやすいでしょう。

パターン指定のバリエーション

 パターンの部分には「*」の他、「?」(任意の1文字)や「[~]」([]内のいずれか1文字、範囲指定も可能)を使うことができます。

 「[]」を使って、「y」と「n」それぞれ、大文字と小文字のどちらでも指定できるようにすると以下のようになります。パターン指定なので、「"y"」のような引用符は不要である点に注意してください。

  1. #! /bin/bash
  2. case "$1" in
  3. [Yy]) #Yまたはy(パターン指定なので引用符は付けない)
  4. echo "YES"
  5. echo "OK"
  6. ;;
  7. [Nn]) #Nまたはn
  8. echo "NO"
  9. ;;
  10. *)
  11. echo "undefined";;
  12. esac
▲yとnを大文字と小文字に対応させた(showyesnoを加工)
  1. $ ./showyesno y
  2. YES
  3. OK
  4. #(引数が「y」だったので「YES」と「OK」が表示された)
  5. $ ./showyesno Y
  6. YES
  7. OK
  8. #(引数が大文字の「Y」でも「YES」と「OK」が表示された)
▲実行結果(showyesno)

●複数のパターンを組み合わせる

 複数のパターンを使いたい場合は「|」で区切って並べます。例えば、「Y」「y」の他に「yes」でも指定できるようにするならば、「[Yy]|"yes"」のようにします。

  1. #! /bin/bash
  2. case "$1" in
  3. [Yy]|"yes") #Y、yまたはyesという文字列
  4. echo "YES"
  5. echo "OK"
  6. ;;
  7. [Nn]|"no") #N、nまたはnoという文字列
  8. echo "NO"
  9. ;;
  10. *)
  11. echo "undefined";;
  12. esac
▲大文字と小文字の「y」と「n」の他、「yes」「no」にも対応した(showyesnoを加工)○●全ての大文字と小文字の区別をなくす

 先ほどの例では「yes」には対応しましたが、「YES」や「Yes」には対応していません。

 少々読みにくくなりますが、「[Yy][Ee][Ss]」のように書くことで、大文字と小文字に対応させることができます。これは、1文字目が「Y」または「y」、2文字目が「E」または「e」、3文字目は「S」または「s」という意味です。また、1文字だけで「Y」または「y」というのも有効にしておきたいとすると、次のようになります。

  1. #! /bin/bash
  2. case "$1" in
  3. [Yy]|[Yy][Ee][Ss])
  4. echo "YES"
  5. echo "OK"
  6. ;;
  7. [Nn]|[Nn][Oo])
  8. echo "NO"
  9. ;;
  10. *)
  11. echo "undefined";;
  12. esac
▲大文字と小文字の「y」「yes」「n」「no」に対応した(showyesnoを加工)

●シェルオプションで大文字と小文字の区別をなくす

 大文字と小文字の区別をなくすシェルオプション「nocasematch」を有効にすると、case文のパターン判定でも大文字と小文字が区別されなくなります。

 ここではシェルスクリプトの先頭で、「shopt」コマンド(bashの組み込みコマンド)で「nocasematch」を有効にしています。この設定はシェルスクリプトの中でのみ有効です。

  1. #! /bin/bash
  2. shopt -s nocasematch #大文字と小文字を区別しない
  3. case "$1" in
  4. "y"|"yes")
  5. echo "YES"
  6. echo "OK"
  7. ;;
  8. "n"|"no")
  9. echo "NO"
  10. ;;
  11. *)
  12. echo "undefined";;
  13. esac
▲シェルオプションで大文字と小文字の区別をなくした(showyesnoを加工)

●大文字と小文字を統一してから比較する(コマンド実行結果によるパターン分岐)

 元の文字列(ここでは$1)を、いったん全て大文字または小文字に変換した上で比較するという方法もあります。

 例えば、「tr」コマンドならば、「tr A-Z a-z」で大文字を全て小文字に、「tr a-z A-Z」で小文字を全て大文字に変換できます。

 trコマンドは標準入力から受け取った文字列を処理するので、echoコマンドとパイプでtrコマンドに渡します。具体的には「`echo $1|tr A-Z a-z`」のように指定します。

 このように、case文とバッククオートを組み合わせることで、コマンドの実行結果を使ってパターン分岐させることができます。

  1. #! /bin/bash
  2. case `echo "$1"|tr A-Z a-z` in #引数を小文字に変換
  3. "y"|"yes")
  4. echo "YES"
  5. echo "OK"
  6. ;;
  7. "n"|"no")
  8. echo "NO"
  9. ;;
  10. *)
  11. echo "undefined";;
  12. esac
▲trコマンドで引数を全て小文字にした(showyesnoを加工)

●bashの変数展開で大小文字を統一してから比較する

 bashのバージョン4以降の場合、「${変数名^^}」で全て大文字、「${変数名,,}」で全て小文字、のような値の取得が可能です。

 そこで、trコマンドを使わなくても、以下のようにすることで引数を小文字に統一できます。

  1. #! /bin/bash
  2. case ${1,,} in #引数を全て小文字で取得
  3. "y"|"yes")
  4. echo "YES"
  5. echo "OK"
  6. ;;
  7. "n"|"no")
  8. echo "NO"
  9. ;;
  10. *)
  11. echo "undefined";;
  12. esac
▲${変数名,,}で引数を全て小文字にした(showyesnoを加工)

 この他にも以下のような指定方法があります。全体を変更するものと、先頭文字だけを変更(2文字目以降には何もしない)するものがあります。

●指定方法と結果
指定方法 意味 変換例
ABC abc Abc aBC
${変数名^} 1文字目だけ大文字にする ABC Abc Abc ABC
${変数名^^} 全て大文字にする ABC ABC ABC ABC
${変数名,} 1文字目だけ小文字にする aBC abc abc aBC
${変数名,,} 全て小文字にする abc abc abc abc
${変数名~} 1文字目だけ大文字小文字を反転させる aBC Abc abc ABC
${変数名~~} 大文字小文字を全て反転させる abc ABC aBC Abc

筆者紹介

西村 めぐみ(にしむら めぐみ)

もともとはDOSユーザーで「DOS版UNIX-like tools」を愛用。ソフトハウスに勤務し生産管理のパッケージソフトウェアの開発およびサポート業務を担当、その後ライターになる。著書に『図解でわかるLinux』『らぶらぶLinuxシリーズ』『Accessではじめるデータベース超入門[改訂2版]』『macOSコマンド入門』など。地方自治体の在宅就業支援事業にてMicrosoft Officeの教材作成およびeラーニング指導を担当。会社などの“PCヘルパー”やピンポイント研修なども行っている。

Copyright © ITmedia, Inc. All Rights Reserved.

スポンサーからのお知らせPR

Linux �� OSS 險倅コ九Λ繝ウ繧ュ繝ウ繧ー

譛ャ譌・譛磯俣

注目のテーマ

4AI by @IT - AIを作り、動かし、守り、生かす
Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。