Hatena::ブログ(Diary)

adsaria mood このページをアンテナに追加 RSSフィード

2010-01-07 bashの正規表現マッチングの使い方

bash正規表現マッチングの使い方

あるフリーウェアのインストールbashプログラムを見ていたら次の様なものがあった。(以下の例は簡略化してある。)

STRING="abc"
if [[ "$STRING" =~ "^ab[cd]$" ]]; then
	echo "matched"
else
	echo "unmatched"
fi

if文の条件表現の中に“=~”というオペレータがある。manを見ると =~ オペレータは文字列正規表現と比較するとある。知らなかった。bash文字列比較で正規表現が使えるとは。私は正規表現比較が必要な時はgrepに喰わせて判断していたのだが、これを使えば簡単にできる。

ところが、だ。上のプログラムが期待通りに動かない。上の例では =~ の左辺と右辺の正規表現はマッチするはずだが、結果は“unmatched”。色々と正規表現を変えてみたが、どれとしてマッチングしない。しかし、if文を次のように変えると期待通りに動く(当たり前なのだが)。

if [[ "$STRING" =~ "abc" ]]; then

"abc"以外の正規表現ではマッチングしない。bashバグか? bashのバージョン3.2.39でも4.0.33でも結果は同じ。そんな長い間バグが修正されてない訳もないので、これは使い方が悪いのだろう。(人のプログラムを疑う前に先ず自分を疑おう!)

で、色々とやってみたら、プログラムを次のように変更するべきだと分かった。

STRING="abc"
if [[ "$STRING" =~ ^ab[cd]$ ]]; then
	echo "matched"
else
	echo "unmatched"
fi

つまり正規表現全体を""(ダブルクォート)で囲んではいけないのだ。ダブルクォートで囲んだ "^ab[cd]$" は正規表現ではなく ^ab[cd]$ という文字列として解釈される。“[[”は外部コマンドではなく、単なるbashのオペレータの1つなので、それに渡す引数はダブルクォートで囲む必要はない。逆に、もし“[”のような外部コマンド(“/usr/bin/[”)に渡すのであれば、ダブルクォートで囲む必要があるが。

分かれば単純な話だが、結構ハマった(1時間位?)。

しかし、このフリーウェアのインストールプログラムはちゃんとテストしてリリースしたのだろうか? 簡単なテストで直ぐに正常に動かないことが分かるはずなのに。う〜ん、このソフトウェアの品質に疑問符がついてしまった。(“フリーウェア”といっても、ちゃんとしたメーカーがリリースしているソフトウェアなのだが。)

まぁ、でも、これでbash正規表現マッチできることがわかったので、これは色々と使えそうだ。

daisuke-mdaisuke-m 2011/05/20 12:20 こちらのエントリで、私のトラブルを解決できました。ありがとうございます。
ちなみに、下記リンク先にもある通り、ある条件下(詳細不明)ではダブルクオートがついていても動くケースがあるようです。恐らく、フリーウェア作成者も、ダブルクオートで通る環境下でスクリプトを書いたのだと思います。
https://gist.github.com/982239

daisuke-mdaisuke-m 2011/05/20 12:32 ある条件下、が明らかになりました。bash 3.1だとダブルクオート付きでも動くそうです。
man bashのcompat31の項参照。

adsariaadsaria 2011/05/20 19:52 daisuke-m様、

> ある条件下、が明らかになりました。bash 3.1だとダブルクオート付きでも動くそうです。
> man bashのcompat31の項参照。

manにはズバリ書いてありましたね。勉強になりました。ありがとうございます。
3.1では(ダブル)クォート付きが仕様だったのですね。

ちなみに、件の会社には“動かないよ。ダブルクォート要らないんじゃない?”と連絡したのですが、”問題なく動いている。ダブルクォートは必要と思う。”と返答が来たので、それ以上は突っ込んでません。きっと古いシステムで検証していたのでしょう。

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

リンク元