LoginSignup
4
6

More than 5 years have passed since last update.

grepと正規表現(regex)

Posted at

はじめに

この記事は、はてなダイアリーの同タイトルのものを、Qiitaのマークダウンの練習で移植したものです。:grinning:
http://d.hatena.ne.jp/namikawamisaki/20180206

(ここから)

いまさらこれやってもすでに、ぼうだいな量のドキュメントがあるので、何をいまさらという感じですが。自分の復習つうか自分が喋るならどうやってたかな(昔某所で研修してた気がする)というのを思い出す感じで書いてみます。

対象としては初学者。ほんとの基礎基礎はできてて、まだパイプとリダイレクトとかはいまいちわかってない人あたり。

今回のトピック

  • 検索と「grepする」
  • grepの使い方
  • 正規表現とは(ちょっとPerlの世界寄り)
  • マッチする(Perlの世界寄り)
  • ワイルドカード #とは

検索と「grepする」

「ググる」はもうGoogleで検索するをとびこえてYahoo!でも「ググる」っていう人がいるらしい。ウェブサイトから、何らかの質問の回答を得たいと思って、あるいは電車の時間を調べるために、ひとは検索する。

一方grep(ぐれっぷ)は、grep(1)1 には”print lines matching a pattern”とあり--パターンマッチする「行」を「表示」する。

grepの使い方

grepの基本的な使い方は、2種類になるかと思う。
1. ターゲットファイル内のパターンマッチ
2. コマンド実行結果のパターンマッチ

下記は1つ目の「ターゲットファイル内のパターンマッチ」について記した。ターゲットファイルの中身は、catというコマンドで表示している。

$ cat ./file1.txt
abcdefghijklmnopqrstuvwxyz
$ grep hoge ./file1.txt
$

(カレントディレクトリ内にある)test1.txt の内部に、「hoge」のパターンを含む行があるかをgrepコマンドで調べ、その結果何もなかったということを示している。

$ cat ./file1.txt
abcdefghijklmnopqrstuvwxyz
$ grep hijk ./file1.txt
$ abcdefghijklmnopqrstuvwxyz
$

hijkはfile1.txtに含まれているため、その行が表示される。(システムによってはhijkの部分に色がつくこともあるだろう。)

「コマンド実行結果のパターンマッチ」は、実務で利用頻度が上がるのではないだろうか。大量のログなどから目的のパターンにあう部分を抜き出す、といった作業でよく使っている。下記の例では、そのままRPMパッケージ数を出すと1484行出力されるが、kernelという文字を含むパッケージだけにしぼって表示している。

$ rpm -qa | wc -l
$ 1484
$ rpm -qa | grep kernel
kernel-xxxxxxxxx
kernel-xxxxxxxxx
kernel-devel-xxxxxxxxx
kernel-devel-xxxxxxxxx
kernel-headers-xxxxxxxxx
kernel-tools-xxxxxxxxx
kernel-tools-xxxxxxxxx
$

オプション有りでの使い方

grepコマンドにはオプションがある。個人的に利用頻度が高いのは、vicあたり。
くさるほど実例を書いたサイトがあるので、ここでは逆引き的にメモしておく。

こうしたい時 こうする
hogeって書いてる行は不要 grep -v hoge ./targetfile.txt
hogeだけじゃなくてHogeもHOGEもとりあえず探す grep -i hoge ./targetfile.txt
hogeって書いている行をカウントする grep -c hoge ./targetfile.txt
hogeって書いていない行をカウントする grep -cv hoge ./targetfile.txt

正規表現とは(ちょっとPerlの世界寄り)

※なんでPerl寄りって書いてるかというと私がPerlから正規表現にふれてたから

grepの後の文字列を、正規表現で記載することにより、さらに(柔軟に)ファイル等から文字列を探すことができる。

$ cat ./file1.txt
abcdefghijklmnopqrstuvwxyz
$ grep 'h.j' ./file1.txt
abcdefghijklmnopqrstuvwxyz
$

「h.j」は「h→何か1文字→j」を示す。よって、「h..j」では結果がないことになる。

$ cat ./file1.txt
abcdefghijklmnopqrstuvwxyz
$ grep 'h..j' ./file1.txt
$

正規表現を勉強するとなるとそれこそ、本にすればフクロウ本レベルになるし、ドキュメントを追うとものすごく広く深くはまっていく。はまるとおもしろい。そのへんは気に入った本やウェブサイトを見てもらうとして、文頭・文末の表現あたりは、見たことがなかったら今見ておいていいかなと思う。詳しくはregex(7)あたり。

  • 文頭→^
  • 文末→$

正規表現で^hogehogeは、「hogeからはじまるか」か、「hogeを含んでいるか」と意味が違ってくる。後者は「hogeからはじまる」も含まれることに注意。

^とか$は、「メタキャラクタ」といって正規表現で特別扱いされる。
regex(7)だと

  • ^.[$()|#+?{\

で、Perlの世界では

  • {}^$.|#+?\

がそれに相当する。もし、そのものを文字として、パターンマッチをしたいときは、前に「半角の¥」を置く。

$ cat file2.txt
abc(def)ghi
$ grep ) ./file2.txt
Too many )'s.

$ grep \) ./file2.txt
abc(def)ghi

マッチする(Perl寄り)

※なんでPerl寄りって書いてるかというと(略)

入門としては「一致する文字列を含む行を出す」くらいでいいと思う。もう一歩すすめるとしたならば、正規表現に「マッチ」しているのはどこか、ということを意識していく必要がある。

参考として、Perlのドキュメント、perlrequick2に記載されている部分を引用する。

    "Hello World" =~ /o/;       # matches 'o' in 'Hello'
    "That hat is red" =~ /hat/; # matches 'hat' in 'That'

1行目は「oを含む行」で取り出そうとしている。この文章では2回oが出てきて、Perlの世界では先のHelloのoにマッチする。

2行目は、そのルールでいくとThatのhatにマッチということになる。

    "cats"          =~ /c|ca|cat|cats/; # matches "c"
    "cats"          =~ /cats|cat|ca|c/; # matches "cats"

これは「cats」という文字列についてだけど、正規表現としてはcでもcaでもcatでもcatsでもマッチする。書き方としては「最初に書いたやつ」が優先されるので、1行目の場合はcでマッチして、2行目の場合はcatsでマッチして、となる。

ワイルドカード #とは

あとよく質問があるのが、「ワイルドカード」との違い。むかしは「また自分で調べておいてね」とかでぼんやりさせてしまってたけど、あらためて見直すと、もっと勉強しないとけないなと思った。のでここにはメモを置いておくので、あとはみなさんで。(結局なげるんかい)

  • 正規表現では*は「直前の文字の0回以上の繰り返し」3
  • ワイルドカードの*は「任意の数の文字に一致」4
$ ls
fil.txt  file.txt  file3.txt
$ ls | grep "file#"
fil.txt
file.txt
file3.txt
$ ls file#
file.txt  file3.txt

この例は、正規表現file#は

  • filときて
  • eが0回以上の繰り返し
  • を含むもの なので、fil.txtも、file.txtも、file3.txtも該当するし、 ワイルドカードのfile#は
  • fileときて
  • 任意の数の(文字数の)文字に一致

だから、fil.txtは含まれず、file.txtとfile3.txtが該当することになる。

参考にしたもの

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6