tailコマンドって-c使うと超速い

Twitterでつぶやいたら意外と知られて無かったので記事にしておきます。 Linuxとかで巨大なログファイルとかを扱うときに、headやtailというコマンドで先頭から何行とか 末尾から何行を見たい時があると思います。

例えばアクセスログで末尾から10000000行目辺りをみたいとかいうときに

$ tail -n 10000000 access_log | head

とかするとかなり遅いと思います。これはログの後ろの方から読み込みながら 行数を計算しているからで、10000000行分数えないとどこから表示すればいいのかわからないので なかなか結果が返ってこなくてヤキモキしてしまいます。

こんなときに、-cというオプションを使うと超高速で結果が返ってきます。-cというのは

   -c, --bytes=N
          output the last N bytes

とある様に、ファイルの末尾からNバイト分を表示してくれます。内部的にはファイルの末尾から Nバイトだけlseek(ポインタを移動するイメージ)したところから表示すればいいことが自明なので すぐに表示を始めることができます。

$ time tail -n 1000000 hogehoge.log | head > /dev/null

real    0m35.462s
user    0m0.156s
sys     0m0.305s

$ time tail -c 10000000000 fugafuga.log | head > /dev/null

real    0m0.011s
user    0m0.000s
sys     0m0.001s

大抵のログには各行にタイムスタンプがあると思いますので、-cの数を適当に調整しながら headで先頭を見るというのを何度か繰り返して、欲しい辺りを探すと良いと思います。

ちなみにheadだと-cも遅いですね。ソース読めばなんか分かるのかも知れないですが 誰か教えて下さい><

$ time head -c 10000000000 hogehoge.log | tail > /dev/null

real    0m47.826s
user    0m1.034s
sys     0m1.671s

間違っても、vimみたいなエディタで巨大ファイルを開こうとしないようにしてくださいね。

noconoco 11-01-22 (土) 10:56

headも同じ条件で処理速度を評価するなら、
time head -c 10000000000 hogehoge.log | head
としなくてはいけないのではないでしょうか。
(tailだとheadの処理が終了するまで待たなくてはいけない)
ソースリーディングは以下に丁度良い情報がありましたよ。
http://techblog.yahoo.co.jp/cat207/how_to/headtail/

とおりすがり 11-01-22 (土) 13:30

開いて確認するだけなら lv コマンドでいいよね。

level 11-01-24 (月) 22:18

最初の方も言ってるとおり、
tail|headだとパイプをデータが少し流れた時点でheadが終わって、tailも終わる(終わらされる)けど、
head|tailだと全部のデータがパイプを通る必要があるからでしょう。

riywo 11-01-25 (火) 0:33

headについてアドバイスありがとうございます。

tail | headでは末尾から数えて〇〇辺りを探したいんで、ちょうど逆にすると
先頭から〇〇辺りを探したいのでhead | tailにしたんですが、たしかにそのとおりですね。

巨大ファイルで先頭からいくらか行ったところをちょろっと見るにはどうするのが速いんでしょうね。