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 にしたんですが、たしかにそのとおりですね。

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