2011-10-31

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 する。

  • バッファサイズ分読み込む

  • バッファが指定行数なかったら、更に読み込む

  • 指定行数に達したら、それを表示する

  • 指定行数に達するまで、その内容はメモリに保持される。


ってことだった。


結論としては



  • 読み込むファイルの大きさが大きくても、問題ない。 ファイルの大きさに従って読み込む量が増えるってことではない。

  • 指定された行数の内容がメモリに保持されるため、数千万行とかでは要注意


ってことでした。

0 件のコメント:

コメントを投稿