読者です 読者をやめる 読者になる 読者になる

カイワレの大冒険 Third

技術的なことや他愛もないことをたまに書いてます

grepコマンドの便利なオプションたち

コマンド コマンド-grep

ログを見たり、何かあった際によくお世話になるgrepコマンドですが、このコマンドも色々便利なオプションがあるので、書いてみたいと思います。内容としては、curlコマンドの便利なオプションたち - カイワレの大冒険 Thirdの続編みたいなものです。

普通に使う

まぁ、まずは普通に使ってみましょう。「grep [options] PATTERN [FILE...]」ということで、単に以下のようにすれば、マッチする行を出力してくれます。

$ head test.list
code=1
code=2
code=3
code=4
code=5
code=6
code=7
code=8
code=9
code=10

こんな感じのファイルがあるとして、code=100とかまでに続くとするなら、

$ grep 'code=80' test.list
code=80

もっと対象を広げて、ざっくり絞り込みたいなら、

$ grep '8' test.list
code=8
code=18
code=28
code=38
code=48
code=58
code=68
code=78
code=80
code=81
code=82
code=83
code=84
code=85
code=86
code=87
code=88
code=89
code=98

ってやればいいだけですね。
個人的にはクォートで囲んで明示するのが好きなので、そう使ってます。文字列であれば、fgrepのほうがいいかもですな。とりあえず、「普通」に使うとこんな感じです。

行数を出力する

マッチした行が何行目にあるか調べたい場合もあるでしょう。そういう場合は、「-n」オプションを使えばよいでしょう。

$ grep -n '10' test.list
10:code=10
100:code=100

特定のパターンを除外する

パッチしたパターンを除外した場合もあるかと思います。tailfしてるんだけど、多すぎるので、絞りこみたいとか。そういう場合は「-v」オプションを使います。

$ grep -n '10' test.list  | grep -v '100'
10:code=10

grep使って、パイプで更にgrepというよりは、「tailf accesslog | grep -v 'なんかのパターン'」みたいな感じで特定のものを除きたいにパイプ経由で使ったほうが便利でしょう。awkとうまく共存させると素敵ですな。

前後を出力する

grepで絞り込めるってのは確かに便利なんですが、その前後にどういうことが書かれているのかをみたいときもあるでしょう。そういう場合は、「-B」や「-A」を使うとよいでしょう。

$ grep -B 2 '20' test.list
code=18
code=19
code=20
$ grep -A 5 '30' test.list
code=30
code=31
code=32
code=33
code=34
code=35

「before-context」と「after-context」の略なので、「大文字」であることを頭にいれておくと覚え易いかもしれません。

正規表現を使う

今までは文字列による検索でfgrepに似た使い方を紹介してきましたが、正規表現を使いたい場合もあるでしょう。その場合はパターンで指定すればいいだけですね。

$ grep '2.' test.list
code=20
code=21
code=22
code=23
code=24
code=25
code=26
code=27
code=28
code=29

まぁ、便利ですな。何も指定しなくても普通に正規表現は使えますが、「-E」オプションを使って、拡張正規表現(Extended Reuglar Exression)を使うよう明示するようにしてもいいかもしれません。

manには以下のように書かれています。

grepは、「基本」正規表現と「拡張」正規表現の2種類の正規表現文法を扱う事ができます。GNU grepでは、どちらの正規表現文法も機能的な違いはありません。他の実装では、基本正規表現は拡張正規表現より能力が低くなっています。

まぁ、難しいことはおいておいて、エスケープがキライという。。。

$ grep -E 'code=[0-9]{3}' test.list
code=100
$ grep 'code=[0-9]{3}' test.list
$ grep 'code=[0-9]\{3\}' test.list
code=100

マッチした部分だけ参照出来ればいい場合も多いので、その場合は「-o」を使いましょう。

$ grep -ioE '2.' test.list
20
21
22
23
24
25
26
27
28
29

ここで使っている「-i」というのは大文字小文字の区別をしないので、入れておく癖をつけておくと楽でしょうな。

あとは正規表現本でも買って、いくつか使えるようになると便利っすな。

$ grep -iE '[[:digit:]]{3}' test.list
code=100

後方参照も便利ですが、拡張正規表現だとはまるので、-Eはつけないほうがいいでしょう。

$ grep 'code=\([[:digit:]]\)\1' test.list
code=11
code=22
code=33
code=44
code=55
code=66
code=77
code=88
code=99

一応手元のGNU grep 2.6.3では以下のように動いてますが、保証できなさそう。

$ grep -E 'code=([[:digit:]])\1' test.list
code=11
code=22
code=33
code=44
code=55
code=66
code=77
code=88
code=99

egrepとか色々出てくると混乱するし、まぁこれだけでももろもろ便利かと。

おまけ 色をつける

おまけですが、--colorオプションは便利っすな。

$ grep --color '10' test.list
code=10
code=100

bashrcとかzshrcにaliasはっておけば、目grepする力も鍛えられるかもしれませぬぞ。

grepで指定オプションを自動付加してくれる環境変数 "GREP_OPTIONS" - 元RX-7乗りの適当な日々にあるようにGREP_OPTIONSという環境変数使ってもよいでしょう。

#### 終わりに

障害時や動作確認等含め、ログを見ることは多々あるかと思います。

その際に適切にコマンド使えばめちゃ楽になりますし、grepも上記にあげたように色々便利なオプションがあるので活用して、是非フィードバック頂ければと。

もちろん、grepだけだとやっぱきつくて、awkやtail(tailf, tail -f, tail -c), xargsなどとうまく合わせることでより実用的になると思うので、その辺はやっていってくなかで慣れるのがよいのかなと思います。

他にもこういう使い方あるよとかあれば是非に!
基本はman読んでくださいですが、zshだと「grep -」まで入力するとこんな感じで補完してくれて素敵なので、興味ある人は是非導入してみてくださいw

$ grep -
--after-context        -A           -- specify lines of trailing context
--basic-regexp         -G           -- use basic regular expression
--before-context       -B           -- specify lines of leading context
--binary-files                      -- specify type to assume for binary files
--byte-offset          -b           -- print the byte offset with output lines
--colour               --color      -- distinguish matching string
--context              -C           -- specify lines of context
--count                -c           -- only print a count of matching lines
--devices              -D           -- specify handling of devices, FIFOs and sockets
--directories          -d           -- specify handling of directories
--exclude                           -- skip files matching specified pattern
--exclude-from                      -- skip files matching pattern in specified file
--extended-regexp      -E           -- use extended regular expression
--file                 -f           -- specify pattern file
--files-with-matches   -l           -- output matching files' names only
--files-without-match  -L           -- output non-matching files' names only
--fixed-strings        -F           -- use literal strings
--help                              -- display help
--ignore-case          -y       -i  -- case-insensitive
--include                           -- examine files matching specified pattern
--invert-match         -v           -- select non-matching lines
--label                             -- provide filename to print for stdin
--line-buffered                     -- flush output on every line
--line-number          -n           -- prefix output with line numbers
--line-regexp          -x           -- force pattern to match only whole lines
--max-count            -m           -- stop after specified no of matches
--mmap                              -- memory map input
--no-filename          -h           -- suppress printing of filenames
--no-messages          -s           -- suppress messages about unreadable
--null                 -Z           -- print 0 byte after FILE name
--only-matching        -o           -- show only matching part of line
--perl-regexp          -P           -- use perl regular expression
--recursive            -R       -r  -- recurse subdirectories
--regexp               -e           -- specify pattern
--silent               --quiet  -q  -- suppress normal output
--text                 -a           -- process binary file as if it were text
--version              -V           -- display version info
--with-filename        -H           -- print filename with each match
--word-regexp          -w           -- force pattern to match only whole words