Linuxのコマンドで使われる正規表現の違い

2020/02/21更新

目次

概要

PerlやJavaScriptの正規表現に慣れていると、+などのメタ文字そのものを表記する場合に\+とエスケープするのは当然であるが、sedやgrepなどのLinuxコマンドで正規表現を使うと、これが逆になっており、+で文字そのもの、\+でメタ文字となることがある。実はこれは、POSIXで標準化されている基本正規表現BRE:Basic Regular Expression)と拡張正規表現ERE:Extended Regular Expression)の違いによるものである。どのようなときにその違いが出るのか、他にはどのような違いがあるのか、調べたのでここにまとめておく。

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

BREとEREの主な違いは以下の表の通りである。BREでは、黄色く示した部分で、通常文字とメタ文字のどちらをエスケープするかがEREと逆になっている。また、※で示した3つ(\+\?\|)は本来BREのものではなく、GNUの拡張によってgrepやsedなどのコマンドが追加で実装しているものである。

基本正規表現(BRE)

拡張正規表現(ERE)

先頭

^

^

末尾

$

$

任意の1文字

.

.

いずれか1文字

[~]

[~]

いずれでもない1文字

[^~]

[^~]

0回以上

*

*

1回以上

\+(※)

+

0回または1回

\?(※)

?

n回

\{n\}

{n}

n回以上m回以下

\{n,m\}

{n,m}

グループ

\(~\)

(~)

または

\|(※)

|

BREでは、いくつかのメタ文字にエスケープが必要となるため、EREに慣れていると不便に感じるが、逆にこれらの文字を多く使う場合は、通常文字としてのエスケープの必要が無くなるので、むしろBREの方が適していると考えることもできる。

エスケープが必要な文字

基本正規表現(BRE)

^ $ . [ ] * \

拡張正規表現(ERE)

^ $ . [ ] * \ + ? { } ( ) |

なお、PerlやJavaScriptなどのプログラミング言語で使われる正規表現は、EREをさらに拡張したものである。

grepやsedでの使い分け

grepやsedコマンドに渡した正規表現は、標準ではBREと認識されるが、-Eなどのオプションを使うことでEREを使うことができる。

例えば、以下のような内容のa.txtがあったとする。

aaaaa
a{5}

このテキストファイルに対してBREとEREでgrepすると以下のようになる。

# 標準ではBREとして解釈される。
grep 'a{5}' a.txt
# a{5}
grep 'a\{5\}' a.txt
# aaaaa
grep 'aa\+' a.txt
# aaaaa(\+はGNUによる拡張)

# -EオプションによってEREを使用できる。
grep -E 'a{5}' a.txt
# aaaaa
grep -E 'a\{5\}' a.txt
# a{5}
grep -E 'aa+' a.txt
# aaaaa

Bashのif [[~]]で使える正規表現

Bashでif [[ $hoge =~ pattern ]]という構文があるが、このときに使える正規表現はEREである。なお、[[~]]の中では、正規表現を/~/"~"などと囲わずにそのまま書くというのが注意点である。

str="aaaaa"
if [[ $str =~ a{5} ]]
then
  echo "OK."
fi

外部リンク