grep を題材に正規表現の説明を簡潔にまとめました
基本の基本しか扱わないので初心者向けの記事となります
とりあえず grep 以外の環境が揃えられない方向けにgithubにリポジトリを作成しました
想定環境
- grep が使える環境ならなんでも
- UbuntuなどUNIXコマンドを使える環境(というかbash)
予備知識
所謂ワンライナーを多様します
何をしてるかと言いますと,
例えば
ls | grep ほにゃらら
という文字列を何回も打ち込むことになりますが,このうち
ls は指定したディレクトリの中身を表示(標準出力)
| は標準出力を次のコマンドの標準入力にするというものです
grepは端的に言うと検索コマンドなので,ディレクトリの中身から特定のファイル名を抜き出すということを行っています
正規表現について
「正規表現」『フリー百科事典 ウィキペディア日本語版』によると
"正規表現(せいきひょうげん、英: regular expression)とは、文字列の集合を一つの文字列で表現する方法の一つである。正則表現(せいそくひょうげん)とも呼ばれ、形式言語理論の分野では比較的こちらの訳語の方が使われる。まれに正規式と呼ばれることもある。"
とある
雑に言うと,様々な文字列をとあるパターンに直そうという話です
例えば
A_000
A_001
A_002
…
A_999
という複数のファイルがあったとします
これらは一般化すると
A_(0~9の数字が三つ)
という風に表せます
書き方は様々あるとは思いますが,今回は grep を題材にお話をするので,以降は grep に限った話をします
grep の基本
grep の由来は, UNIX の太古のエディタ ed のコマンド,g/re/p らしいです
grep は非常に早いコマンドで……と,grep について語っていると長くなってしまうのでさっさと本題に行きましょう
まず始めに grep が扱う正規表現を書き出します.
正規表現 | 意味 |
---|---|
. | 改行文字以外の任意の1文字 |
* | 直前の1文字の0回以上の繰り返しに一致 |
^ | 行頭 |
$ | 行末 |
[ ] | []内の任意の文字。-で範囲指定。[]内の最初の文字が^であればそれ以外という意味 |
+ | 直前の文字の1個以上の連続 |
? | 直前の文字の0または1文字にマッチ |
pattern1|pattern2 | pattern1あるいはpattern2のいずれかにマッチ |
(pattern) | patternをグループ化 |
\ | +やを検索に使いたいときに(例:\+ \) |
以下,問題のすぐ下に解答が乗っているので,ゆっくりスクロールすることをオススメします
実践編
まず,先に挙げた例のようなディレクトリを作ります
そのままでなくてもよいので,以下の様にターミナルに打ち込んでください
mkdir grep_test
cd grep_test
touch A_{000..999}
この A_{000..999}というのは bash のブレース展開という機能です
とても便利なので愛用してます
ともあれ
ls
と打ってみるとA_000~A_999までのファイルができてるはずです
あるいは
ls | wc -l
で 1000 と表示されていれば大丈夫でしょう
ブレース展開のできないシェルを使っている場合は
seq 0 999 | awk '{printf("touch A_%03d\n", $0)}' | sh
などとするのも良いと思います
では,まず始めにこの中から,
A_000 ~ A_099
を抜き出してください
やりかたは簡単で
ls | grep A_0
とするだけ
すると,皆さんの画面にはA_000 ~ A_099が表示されたはずです
では,次の題です
二桁目(10の位)が6のファイルのみを抜き出して下さい
解答は
ls | grep A_.6
これは,"." という文字が任意の1文字にマッチするため成立します
あるいは
ls | grep A_[0-9]6
でもよいかもしれません
これは,"[0-9]"が0-9の数字1文字とマッチするため成立します
では次の題です
最初と同様に B_000 ~ B_999 を作成します
同様に,C_000 ~ C_999 も作成します
また,A_に関しては16進数で作りましょう
ls | grep A_ | xargs rm
touch A_{{0..9},{A..F}}{{0..9},{A..F}}{{0..9},{A..F}}
などと入力すれば十分なはずです
※rm は削除コマンドです.rm A_* でもいいのですが, A_ と * の間にスペースが入ったら悲惨なので(bashの全ファイル展開),できるかぎり事前に消すファイルを表示してxargs(標準出力を引数に与えたコマンドの引数にするコマンド)でrmを使いましょう
まず始めに
上二桁が 99 あるいは下二桁が 99 のファイルを抜き出してください
また,下二桁が 99 のファイルのみも抜き出してください
解答は次の通りです
ls | grep 99
ls | grep 99$
$は行末を表す正規表現なので,99で終わるファイルのみを抜き出してくれます
ではさらにこの中で
999 より大きい数を抜き出してください
解答は次の通りです
ls | grep 99 | grep -v [0-9]9[0-9]
ここでは grep の v オプション(検索に一致しないものを表示)を使っていますが,正規表現を使って
ls | grep -e [A-F]99 -e 99[A-F]
あるいは
ls | grep -e _[^0-9]99 -e 99[^0-9]
でも正解です
grep の -e オプションは明示的にパターンを指定する(通常は第一引数がパターンと見なされる)オプションで,複数指定してあげると OR 条件式のように働いてくれます
オプションを全く使わないのであれば
ls | grep "([A-F]99)|(99[A-F])"
という解答でも良いと思います
これは,"()"でくくられたパターン二つのうちどちらかにマッチすれば出力ということですからOKです
以下は簡単なおさらいです
csvのデータにも同様にしてgrepを扱って色々なことができますよという話です
国民の祝日のcsvファイルを内閣府が配布してます
curl でとってきましょう
curl http://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv | nkf > syukujitsu.csv
この中から,2017年の祝日を取り出してください
cat syukujitsu.csv | grep 2017
次に,八月の祝日を取り出して下さい
cat syukujitsu.csv | grep 20..-08
次に,20日以降の祝日だけ取り出して下さい
cat syukujitsu.csv | grep 2.,
こんなところで,使い方はふんわりと分かったかなと思います
この程度の知識でもファイル整理(よく grep して xargs cp などしている)などには十分役立ちますから,覚えておくといいかもしれません
間違い等ありましたらお教えくださると幸いです