UNIX系のコマンドの多くは、何らかの正規表現に対応している。正規表現というのは短い記述で多くのパターンの文字列に一致させることができるもので、使いこなせるとかなり便利だ。本連載でこれまでに取り上げてきた、行頭に一致する「^」と、行末に一致する「$」も、正規表現の1つである。

どのコマンドの正規表現もよく似ているものの、完全に同じということもなく、それぞれにちょっとずつ意味が違ったり、対応している機能に違いがあったりする。例えば、GNU grep(1)のサポートしている正規表現は強力で、使いこなせればかなり心強い。

GNU grep(1)は複数の正規表現をサポートしているのだが、特に覚えておきたいのが「基本正規表現」と「拡張正規表現」だ。前者はデフォルトで利用できる正規表現であり、後者はgrep(1)にオプション「-E」を指定した場合に利用できる、さらに機能が増えた正規表現という位置付けになっている。

正規表現は一気に説明すると意味がわからなくなってしまいがちなので、汎用性が高くて応用がきくものから紹介していこうと思う。

「1文字に一致」を表す「.」

grep(1)を使う際、はまりがちな正規表現の1つが「.」だ。「.」は、任意の1文字に一致する正規表現となっている。つまり、拡張子との区切りという意味で「.」を指定しても、それは任意の1文字に一致するので、期待したようには機能してくれない。

次の例をご覧いただきたい。5文字の文字列をgrep(1)に流し込んで「.」で一致をかけている。

任意の1文字に一致する「.」

「.」で一致をかけると、12345のうち1と2と3と4と5が一致する。「..」だと、12および34、「…」だと123……と続き、「……」だと何にも一致しないという動作になっていることが確認できる。

「.」は「何らかの1文字」に一致するので、検索したい文字列の長さがわかっていて前後に空白やタブなどの区切り文字がある場合には、前後に区切り文字を指定して「.」を文字数分だけ記述すれば、該当個所を抜き出すことができる。単純な記述だが、覚えておくと結構便利だ。

では、句点としての「.」を指定したい場合にはどうすればよいのだろうか。その場合には「[.]」のように角括弧(ブランケット)の中に「.」を書いたものを使う。または、バックスラッシュに続けて「.」を書くと、「.」そのものを意味する。実行すると、以下のようになる。

「.」を文字として指定する場合

正規表現の利用のややこしさはここにあるのだが、正規表現はシェルでも使われている。さらに、シェルによってサポートしている正規表現やその無効化の方法が違う。マニュアル通りに正規表現を書いたとしても、シェルはそれをシェルのお作法で解釈してしまうため、意図しない動作になることがあるのだ。これを回避するには、まずシェルが記述を正規表現だと認識しないようにする必要がある。

例えば、バックスラッシュはシェルでも特別な意味を持っていることが多い。例えば、grep(1)が「.」を文字として認識するように、前にバックスラッシュを付けて書いたとしても、シェルがそれを勝手に「.」に変換してgrep(1)に渡してしまうのだ。シェルの場合、バックスラッシュを2つ続けた後に「.」を書くか、もしくはバックスラッシュの後に「.」を書いたものを「”」でくくっておくと、「.」が文字としてgrep(1)に値が渡ることが多い。

列挙した文字に一致させる「[]」

「.」を文字のピリオドとして理解させる「[.]」という表記は、実は「ブランケット式」という正規表現の1つを利用したものだ。ブランケットの中に書いた文字が、1文字に一致する。これもかなりよく使う機能なので、まず覚えておきたい。例えば、こんな感じで使うことができる。

ブランケット式で複数の文字から一致させる

grep(1)には大文字と小文字のどちらにも一致させるオプション「-i」があるので必要性が低いのだが、ブランケット式は次のような場合に利用することができる。

ブランケット式の使用例

これは、シェルスクリプトなどでよく使われる表記方法だ。ブランケット式には範囲指定、NOT指定(一致しないものを一致させる)、特定の文字列を表現するショートカット記法が用意されている。これに繰り返し指定などを組み合わせると、短い記述でいろいろなパターンを表現できるようになる。

「習うより慣れろ」の正規表現

正規表現は、本を読んで学ぼうとしてもうまくいかないことが多いように思う。先ほど説明したように、シェルで正規表現を無効化する方法なども覚える必要があるし、経験がないとわからない部分が多いからだ。

とりあえず簡単なところから正規表現を覚えて、それを使ってみるのが最短の習得方法だと思う。使って覚えた正規表現はなかなか忘れないし、覚えた表現はほかのコマンドでも利用できることが多いはずだ。ぜひ、いろいろ試してみていただきたい。