正規表現とは:ワイルドカードとの違い

正規表現(regular expression)は、文字列のパターンを表現するための記法です。「基本的なファイル管理」の記事で扱ったファイル名のワイルドカード(グロブ)とは記法が異なり、grep・sedなど、テキストの内容を検索・加工するツールで使われますワイルドカード(グロブ)については「基本的なファイル管理」の技術解説記事で扱っています。同じ*という記号でも、ワイルドカードでは、パス名の1要素内で通常は先頭が.ではない任意の文字列(/は除く)、正規表現では「直前の文字の0回以上の繰り返し」を意味するなど、解釈が異なる点に注意してください。[1]。

基本正規表現(BRE)と拡張正規表現(ERE)

正規表現には、大きく分けて基本正規表現(BRE、Basic Regular Expression)と拡張正規表現(ERE、Extended Regular Expression)の2つの方言があります。両者の違いは、一部のメタ文字(特殊な意味を持つ文字)をエスケープなしで使えるかどうかです。以下の表は、GNU grep・GNU sedなどで使われる記法です。

メタ文字意味BREでの書き方EREでの書き方
1回以上の繰り返し直前の要素が1回以上続く\++
0回または1回直前の要素が無いか1回\??
選択(OR)いずれかのパターンに一致|`
グループ化複数の文字をひとまとまりとして扱う\(...\)(...)
繰り返し回数の指定直前の要素がn回繰り返す\{n\}{n}

BREでは、これらの記号はバックスラッシュを付けない限り、単なる文字(リテラル)として扱われます。EREでは逆に、そのままメタ文字として機能します。

正規表現の基本的な構成要素

記号意味
.任意の1文字に一致する
*直前の要素の0回以上の繰り返しに一致する
^行の先頭(アンカー)
$行の末尾(アンカー)
[abc]角括弧内のいずれか1文字に一致する(文字クラス)
[^abc]角括弧内の文字以外の1文字に一致する
[0-9]範囲を指定した文字クラス(数字1文字)
^ERROR       # 行頭が「ERROR」で始まる行
[0-9]\{3\}   # 数字3桁の並び(BRE) / [0-9]{3}(ERE)
colou?r      # colorまたはcolour(ERE。BREでは\?が必要)

grep:正規表現でファイルの内容を検索する

grepは、指定したパターンに一致する行を検索して表示するコマンドです。既定ではパターンを基本正規表現(BRE)として解釈し、-Eオプションを付けると拡張正規表現(ERE)として解釈します。

主なオプション効果
-E拡張正規表現(ERE)として解釈する
-F正規表現ではなく、固定文字列(リテラル)として検索する
-i大文字・小文字を区別しない
-vパターンに一致しない行を表示する
-c一致した行数のみを表示する
-n一致した行の行番号を表示する
-rディレクトリ以下を再帰的に検索する(再帰中に見つけたシンボリックリンクはたどらない)
-Rシンボリックリンクもたどってディレクトリ以下を再帰的に検索する
-l一致した行を含むファイル名のみを表示する
grep -n "ERROR" app.log        # 「ERROR」を含む行を行番号付きで表示する
grep -v "^#" config.conf       # コメント行(#で始まる行)以外を表示する
grep -r "TODO" ./src/          # ディレクトリ以下を再帰的に検索する
grep -E "colou?r" file.txt     # 拡張正規表現を使って「color」または「colour」を検索する

|によるOR(選択)

拡張正規表現では、メタ文字の|を使って複数のパターンからいずれかを選択できます。これは論理的なORを表します。

grep -E 'word1|word2' file.txt

このコマンドは、word1またはword2のどちらかを含む行を表示します。

例えば、ログファイルからERRORまたはWARNINGを含む行を検索する場合は、次のように指定します。

grep -E 'ERROR|WARNING' app.log

|で区切った各パターンは、より複雑な正規表現にすることもできます。

grep -E '^ERROR|^WARNING' app.log

この例では、ERRORまたはWARNINGで始まる行を検索します。選択範囲を明確にしたい場合は、丸括弧()でまとめます。

grep -E '^(ERROR|WARNING):' app.log

この例では、ERROR:またはWARNING:で始まる行を検索します。

|はシェルでもパイプとして使われる特殊文字です。そのため、正規表現としてgrepに渡す場合は、通常、パターン全体をシングルクォート' 'またはダブルクォート" "で囲みます。

なお、-Eを付けない基本正規表現では、POSIX標準のメタ文字として|による選択は利用できません。OR検索を行う場合は、次のようにgrep -Eを使うのが基本です。

grep -E 'word1|word2' file.txt

GNU grepなどでは、基本正規表現で\|と記述できる場合もありますが、移植性や可読性を考えるとgrep -Eと|を使用する方法が推奨されます。

egrepとfgrep

egrepはgrep -Eと、fgrepはgrep -Fと、それぞれほぼ同じ動作をする歴史的なコマンドです。多くのディストリビューションでは、これらはgrep本体への簡易的なラッパー(または非推奨の別名)として提供されています。

egrep 'ERROR|WARNING' app.log

上記は、基本的に次のコマンドと同じ意味です。

grep -E 'ERROR|WARNING' app.log

現在はgrep -E・grep -Fという書き方が一般的ですが、出題範囲の用語としてはegrep・fgrepも挙げられています。

sed:正規表現を使ってテキストを編集する

sed(stream editor)は、正規表現を使ってテキストの削除・変更・置換を行うコマンドです。入力を1行ずつ読み込み、指定したコマンドを適用して出力します。sedのパターンは既定では基本正規表現(BRE)として解釈されます。

置換:sコマンド

s/パターン/置換後の文字列/フラグという形式で、パターンに一致した部分を置換します。

sed 's/foo/bar/' file.txt        # 各行で最初に見つかったfooをbarに置換する
sed 's/foo/bar/g' file.txt       # 各行のすべてのfooをbarに置換する(gフラグ=global)

行の削除:dコマンド

dコマンドは、パターンに一致した行を削除(出力しない)します。

sed '/^#/d' config.conf     # コメント行(#で始まる行)を削除して表示する
sed '5d' file.txt            # 5行目を削除して表示する

-nオプションとpコマンド:出力する行を絞り込む

sedは既定ですべての行を出力しますが、-nオプションを付けると自動的な出力が抑制され、p(print)コマンドを明示的に指定した行だけが出力されます。

sed -n '5p' file.txt          # 5行目だけを出力する
sed -n '/ERROR/p' app.log     # ERRORを含む行だけを出力する(grepと似た使い方)

ファイルを直接書き換える:-iオプション

既定では、sedは結果を標準出力に表示するだけで、元のファイルは変更しません。GNU sedでは、-iオプションを付けると、結果を元のファイルに直接書き戻します。-iオプションとバックアップ接尾辞の指定方法は、sedの実装によって異なる場合があります。

sed -i 's/foo/bar/g' file.txt    # file.txtの内容を直接書き換える
sed -i.bak 's/foo/bar/g' file.txt  # GNU sedでは、書き換える前にfile.txt.bakとしてバックアップを残す

補足

  1. ワイルドカード(グロブ)については「基本的なファイル管理」の技術解説記事で扱っています。同じ*という記号でも、ワイルドカードでは、パス名の1要素内で通常は先頭が.ではない任意の文字列(/は除く)、正規表現では「直前の文字の0回以上の繰り返し」を意味するなど、解釈が異なる点に注意してください。 ↩