tail コマンドは大きいファイルの最後の行を取るときにも能率が良い

「アクセスログの最後の1000行ぐらいを抽出して集計するような処理を、数分ごとに実行したいんだけど」なんていう話をしており、ここで tail コマンドが使えるのか調べてみた。

気にしていたのが、 tail コマンドが「最後の1000行」を取得するために、ファイルの最後から1000行を取り出すのか、最初からファイルの内容を全部見ていって、最後の1000行を取り出すのか気になった。

strace -o /tmp/trace tail -10 coreutils-selinux.patch

こんなコマンドを実行して strace の結果を見てみた。

open("coreutils-selinux.patch", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=77599, ...}) = 0
lseek(3, 0, SEEK_CUR)                   = 0
lseek(3, 0, SEEK_END)                   = 77599
lseek(3, 73728, SEEK_SET)               = 73728
read(3, "@@ -1442,7 +1434,7 @@n n /* If u"..., 3871) = 3871
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,  0) = 0x2ab4246d1000
write(1, "+run.n", 6)                  = 6
write(1, "--- /dev/nullt2006-10-03 09:23:1"..., 50) = 50
write(1, "+++ coreutils-5.97/man/chcon.xt2"..., 67) = 67
write(1, "@@ -0,0 +1,6 @@n", 16)       = 16
write(1, "+[NAME]n", 8)                = 8
write(1, "+chcon \- change file SELinux se"..., 47) = 47
write(1, "+[DESCRIPTION]n", 15)        = 15
write(1, "+.\" Add any additional descript"..., 41) = 41
write(1, "+[REPORTING BUGS]n", 18)     = 18
write(1, "+Report bugs to <https://bugzill"..., 56) = 56
read(3, "", 0)                          = 0
close(3)                                = 0

ここから分かった挙動としては、

  • ファイルの最後に seek する。
  • バッファサイズ分読み込む
  • バッファが指定行数なかったら、更に読み込む
  • 指定行数に達したら、それを表示する
  • 指定行数に達するまで、その内容はメモリに保持される。

ってことだった。

結論としては

  • 読み込むファイルの大きさが大きくても、問題ない。 ファイルの大きさに従って読み込む量が増えるってことではない。
  • 指定された行数の内容がメモリに保持されるため、数千万行とかでは要注意

ってことでした。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください