テキストデータに親しみたいエンジニアがよく使いそうなコマンド:「zgrep」コマンドへの道
ふとたまたま、
「圧縮されたアーカイブログにもgrepがかけられる「zgrep」が便利!」という記事を読んで、こんなコマンドあるんだと思い、どうせならテキストデータ生成から色々コマンド使ってみようじゃないかと思い立ったのが、今回の発端。少しでも黒い画面が好きになる人が増えたら幸いです。
ということで、ちょっと試してみた。
まず検証用データを作ってみる。
まぁ、業務に携わってればログとか色々あるだろうけど、せっかくだしコマンドを色々使って、データ作ってみましょう。
まずある程度固まってるデータとして、郵政のページから郵便番号のCSVを取ってくる。wgetとかはテキストデータと関係ないので除外(優しくなくてごめんなさい。書いてて疲れたw)。あと、このCSVはDBサーバに流したりもできるので、便利ですよと。とりあえず解凍。
lzhを解凍するには、lhaというコマンドを使います。こういうとこから持ってきたりすればいいかな。
$ lha x ken_all_rome.lzh ken_all_rome.csv - Melted : oooooooooooooooooooooooooooooooooooooooooo
んで、ファイルサイズを確認してみる。そのとき使うのが、duコマンド。ちなみに、解凍したらこれぐらいのファイルサイズ。
$ du -sh * 8.4M ken_all_rome.csv 984K ken_all_rome.lzh
行数を調べたいときは、パイプを使って、wcに食わせましょう。
$ cat ken_all_rome.csv | wc -l 123008
12万行だと少ないので、増やしてみる。繰り返せばいいだけなので、forを使うんだけど、1から100まで全部書いたら疲れるので、seqコマンドで連番を発生させる。
$for i in `seq 1 100` >do > cat ken_all_rome.csv >| dup_ken.csv >done
んで、増やしてみた。
$ du -sh * 839M dup_ken.csv 8.4M ken_all_rome.csv 984K ken_all_rome.lzh
当然行数は、100倍の1200万行。
$ cat dup_ken.csv | wc -l 12300800
そしたら、zgrepのためにgzipで圧縮する。オプションなければ固めてくれます。
$ gzip dup_ken.csv
まぁ、妥当な感じでファイルサイズ縮小
$ du -sh * 97M dup_ken.csv.gz 8.4M ken_all_rome.csv 984K ken_all_rome.lzh
一応、中身確認。パイプでheadコマンドに渡すことで、先頭だけを標準出力に渡してくれます。
$ gzip -dc dup_ken.csv.gz | head 01101,"0600000","IKANIKEISAIGANAIBAAI","CHUO-KU SAPPORO-SHI","HOKKAIDO",0,0,0,0,0,0 01101,"0640941","ASAHIGAOKA","CHUO-KU SAPPORO-SHI","HOKKAIDO",0,0,1,0,0,0 01101,"0600041","ODORIHIGASHI","CHUO-KU SAPPORO-SHI","HOKKAIDO",0,0,1,0,0,0 01101,"0600042","ODORINISHI(1-19-CHOME)","CHUO-KU SAPPORO-SHI","HOKKAIDO",1,0,1,0,0,0 01101,"0640820","ODORINISHI(20-28-CHOME)","CHUO-KU SAPPORO-SHI","HOKKAIDO",1,0,1,0,0,0 01101,"0600031","KITA1-JOHIGASHI","CHUO-KU SAPPORO-SHI","HOKKAIDO",0,0,1,0,0,0 01101,"0600001","KITA1-JONISHI(1-19-CHOME)","CHUO-KU SAPPORO-SHI","HOKKAIDO",1,0,1,0,0,0 01101,"0640821","KITA1-JONISHI(20-28-CHOME)","CHUO-KU SAPPORO-SHI","HOKKAIDO",1,0,1,0,0,0 01101,"0600032","KITA2-JOHIGASHI","CHUO-KU SAPPORO-SHI","HOKKAIDO",0,0,1,0,0,0 01101,"0600002","KITA2-JONISHI(1-19-CHOME)","CHUO-KU SAPPORO-SHI","HOKKAIDO",1,0,1,0,0,0
どんだけ早いのか検証してみる
ということで検証データを作ったので、それを使って検証してみましょう。
適当に思いついた条件で検索かける。パイプでfgrepコマンドで検索条件を指定すればよいだけ。wcコマンドは前述したとおり。
$ gzip -dc dup_ken.csv.gz | fgrep '060' | wc -l 172500
実行時間計るのはtimeコマンド。スピードはこれくらい。二回実行してよいのだろうか…
$ time gzip -dc dup_ken.csv.gz | fgrep '060' | wc -l 172500 real 0m11.343s user 0m10.030s sys 0m1.314s
個人的に1200万行を11秒で検索するfgrepはすごいなーと感心したり。たいしたCPUじゃないけど、いい時代なもんだ。
(grepでも大して変わらなかったから放置)
んで、やっぱりawk使いたくなったので、無理やり使ってみる。インクリメントさせてもよかったかも。まず行数間違ってないか確認。シングルクォートで正規表現をまず書いて、そのあとに処理する内容を書く。ここではただ表示するだけなので、print。
$ gzip -dc dup_ken.csv.gz | awk '/060/ {print}' | wc -l 172500
fgrepと一致したので、計測してみた。新たなに加えるコマンドはなし。
$ time gzip -dc dup_ken.csv.gz | awk '/060/ {print}' | wc -l 172500 real 1m44.781s user 1m41.886s sys 0m2.775s
やっぱ、これぐらいはかかっちゃうかぁと。
んで、本日の出番の「zgrep」。zgrep 条件 ファイル名の順に指定する模様。
$ zgrep '060' dup_ken.csv.gz | wc -l 172500
スピードはfgrepと変わらんかった。
$ time zgrep '060' dup_ken.csv.gz | wc -l 172500 real 0m11.396s user 0m9.982s sys 0m1.416s
終わりに
まぁ、zgrepを単に使うだけだったら、こんなことする必要一切ないんだけど、どうせなら色々使えたほうが選択肢も増えるので、ついでに色々書いてみました。
速度的な驚きはなかったですな。
こういうとき、どんなシステムコール呼び出されてるのかトレースしたら面白いかもなーと思いつつ、そこまでやってない。すいません… 誰か(ry
まぁ、仕事していればアクセスログとか桁数の多いデータ、手元にあるかもだけど、ぱっと作って、こう色々できるのはわりとコマンドの面白いとこなんじゃないかなーと思ったり。
単にzgrep使いたいだけだったのに、なんでこんな方向に行ってしまったんだろうか… オプションの説明とかどこ行った…
ほかにも、sortとかuniqとか、awkももっと変態的に(ry
P.S.
基礎から学びたい人は、一応真面目に書いた「今春サーバを触っていくのにびくびくしてる人が1週間ですべき7のこと」のほうがよいかもだったり。一応とか…