thasmto's blog

フロントエンドエンジニアやってます。プログラマーとして学んだことや考えていることを投稿するブログです。

grepコマンド基礎

シェルスクリプトやコマンドを使った開発や作業の効率化に興味があり、 Software Design 2021年6月号に掲載されていた「シェルとコマンドで使う正規表現」という章を読んだのでまとめる。

基本正規表現(BRE)

grepでデフォルトで使用されている正規表現は、基本正規表現(Basic Regular Expressions、BRE)と呼ばれれるもの。 特殊な意味をもつ文字は.[]^$*の6文字だけ。他の記号も使えるがエスケープが必要。

シェルで正規表現を書くときは基本的にシングルクォートで囲む。 そうしないとシェルが「*」や「$」などの文字列を別の意味で解釈してしまう。

$ grep '(.*)' text.txt
(きん)の網はゆらゆらゆれ、泡はつぶつぶ流れました。
『ふうん。しかし、そいつは鳥だよ。かわせみと云うんだ。大丈夫(だいじょうぶ)だ
『いいいい、大丈夫だ。心配するな。そら、樺(かば)の花が流れて来た。ごらん、き
 泡と一緒(いっしょ)に、白い樺の花びらが天井をたくさんすべって来ました。
$ grep -o '(.*)' text.txt
(げんとう)
(ひき)の蟹(かに)
(は)
(はがね)
(てんじょう)を、つぶつぶ暗い泡(あわ)
(つぶ)
$ grep -o '([^(]*)' text.txt
(げんとう)
(ひき)
(かに)
(は)
(はがね)
(てんじょう)
(あわ)
(つぶ)

[^(]でかっこの中のかっこを否定している

拡張正規表現(ERE)

grepには-Eというオプションが用意されている。これは拡張正規表現(Extended Regular Expressions、ERE)というクラスの正規表現を使うためのオプション。

GREとEREを比較

$ cat numbers.txt | grep '^.....-.....-.....$';
$ cat numbers.txt | grep -E '^.{5}-.{5}-.{5}'

BREでは繰り返す数だけ.を入力する必要があるが、EREでは{5}というように任意の文字が5個続くという表現を短い文字数で表現できる。 BREでもエスケープを使えば表現可能。

$ cat numbers.txt | grep '^.\{5\}-.\{5\}-.\{5\}'

{}による個数の指定には、{m,n}という記法もあり、この記法は「m個以上n個以内」という意味になる。

$ cat numbers.txt | grep -E '^.{2,3}-.{,2}-.{2,}$'

ほか、EREでエスケープなしで使える記号には、正規表現をグループ化する「()」や、1文字以上の繰り返しを表す「+」、直前に書いた文字が0文字か1文字存在することを表す「?」、()の中でORを表す「|」がある。

Perl互換正規表現(PCRE)

BRE、EREの違いは記号をエスケープするかどうかぐらいだったが、grepではPerlで使われる強力な正規表現も利用できる。 この正規表現Perl互換性正規表現Perl Compatible Regular Expressions、PCRE)と呼ばれ、同じ名前でライブラリ化されている。 grepでもこのライブラリが使え、-Pオプションで呼び出すことができる。

※ただし、macOSではPCREがサポートされていないので、別途GNU版のgrepをインストールする必要がある。インストールしたコマンドはggrepというコマンド名で登録される。

$ brew install grep
$ ggrep -P '.*' text.txt

RCREを使って正規表現を書き換える

$ cat numbers.txt | grep -Po '^\d{2,3}-\d{2,3}-\d{2,3}$'
$ cat numbers.txt | grep -P '^(\d{2,3})-(?1)-(?1)$'

?番号を使うと、()で囲んだ正規表現を再利用できる。 ?1の場合は一つ目の()の中の正規表現なので、\d{2,3}を再利用している。

おわり