それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bashでif に正規表現を使った文字列マッチ条件分岐

bash の使い方

bash の使い方正規表現編です。

bash正規表現マッチのif も出来ます。

Version 3.2 くらいから、=~ によるマッチ判断ができるようになっています。

正規表現マッチで条件分岐の例

とてもかんたんなマッチングの例を見ておきましょう。

name='<h1>takuya</h1>'
if [[ $name =~ takuya ]] ;
then
  echo match
fi

if の条件のなかに [[ ]] のダブルブラケットを書くのがポイントです。正規表現はクオテーションは不要です。クオートしたら動かないので注意してね。

これで、文字列が存在したらマッチ。文字がアレば何かする事ができます。

すこし複雑な正規表現マッチ

最初の例だと単なる文字列マッチと区別がつかないので、もうすこし正規表現らしいマッチングをしてみます。

電話番号にマッチ
tel='09012345678'

if [[ $tel =~ [0-9]{3}-?[0-9]{4}-?[0-9]{4} ]] ;
then
  echo match
fi

よく見る正規表現で、数字の出現と回数、特定の文字列の有無が判断できます。

ポイントは[[ ]] のダブルブラケットの中で変数と文字列が展開され、マッチングしていることにあると思います。 つまり、[[ $name =~ ^REGEX$ ]] [[ STRING =~ ^REGEX$ ]] に展開され、マッチするか判断されていると考えられます。

このことは、次に紹介する、正規表現を変数に埋める処理に関係します。

またクオートしなかったのも同じ理由であると考えられます。 [[ $name =~ "^REGEX$" ]] のように書いてしまうと クォートを含めた"^REGEX$"正規表現として解釈されてしまうようです。

正規表現を変数に格納してマッチング。

正規表現if の中に書くのは後々のトラブルの種というか、悩みのタネになりそうです。

正規表現を変数に入れてマッチングをしてみたいと思います。

# 正規表現を変数に入れた場合
tel='09012345678'
regex='[0-9]{3}-?[0-9]{4}-?[0-9]{4}'

if [[ $tel =~ $regex  ]] ;
then
  echo match
fi

先程の例の改造版です。ケータイ電話番号の正規表現マッチの処理で、正規表現の部分を変数regex に格納した例になります。

前項の説明を借りると[[ $tel =~ $regex ]][[ 09012345678 =~ [0-9]{3}-?[0-9]{4}-?[0-9]{4} ]] に展開され、その後 [[ ]]の内部でマッチングの処理が行われていると考えると理解しやすいでしょう。

正規表現を使えば OR 記述が少し簡潔になる

if 文の中に文字列で== をいくつも列挙するのは少々しんどい。あとで読みづらいので、正規表現を使うと少し簡潔書くことも出来ます。

まぁ正規表現だから当たり前なんですけどね。簡潔な書き方なのはうれしいですね

正規表現のORを使う例
function match_test(){
  printf "%-18s: " "$1"
  if [[  $1 =~ apple|pen   ]];  then
    echo match
  else
    echo dose not match
  fi
}
match_test "Hello world."
match_test "This is a apple."
match_test "This is pen."
match_test "This is a boy."
# 上記の実行結果
Hello world.      : dose not match
This is a apple.  : match
This is pen.      : match
This is a boy.    : dose not match

大文字・小文字の区別

正規表現を使う上で、重要になるのが大文字小文字の区別になります。Case SensitiveCase Insensitive かは、正規表現を使う上で避けて通れない知識になります。bash では正規表現を使うときにshoptで設定されたシェルのオプションフラグを参照してます。

# シェルのオプションの確認
$ shopt | grep case
nocaseglob      on
nocasematch     off

わたしの場合、正規表現Case Sensitive、GlobではCase Insensitiveで利用しています。ご自身で好きな設定をすることが出来ます。もし設定を常時有効にしたい場合は、下記のコマンドを~/.bashrcに記述しておけば設定を永続化出来ます。shopt の使い方は別に記事を書くのでそちらも参考してください・

# 大文字小文字を区別しない設定 Senstive
shopt -s nocasematch
# 大文字小文字を区別する設定 Insensitive
shopt -u nocasematch

正規表現の他に比較で使えるもの

正規表現マッチの他にも、文字列の比較には色々使えます。

bashでは文字列の比較に次のようなものが使えます。

  • 正規表現(今回紹介したもの
  • glob マッチ
  • == によるマッチ
  • grep(コマンド) によるマッチ

人によってシェルスクリプトでの書き方は異なるでしょうが、わたしは正規表現bashだけで使えるのがとても気に入っています。

後方参照

マッチした文字列の後方参照で再利用する方法は、別の記事にしています。

bashの正規表現マッチで後方参照 - それマグで!

追記

zsh の場合でも 同様にできる。 zsh も進んでますね。

追記

sh の場合は 、 expr を使う expr を使うときの記述例は別エントリに書いた → シェル ( /bin/sh ) での正規表現マッチ。 - それマグで!

まとめ

bash のコードが読みにくいと予断をもってるひとも、コレを見てbashの印象がすこし好転してくれるではないでしょうか。読者がbashを"再"発見されることに期待を寄せて。

2019-08-23

マッチした文字列の取得方法(後方参照)ついてのリンクを追加

2020-06-09追記

zsh についての記述を追加 。 exprについての記述を追加。

参考資料