缘起
有一个日志文件,很大很大;当想看最新的写入的时候,首先想到的是tailf,大概是因为 tailf 比 tail -f 少2个字符吧。但是,许久没有输出,感觉不应该的,不管文件有多大,从文件尾部开始查还是比较快的;换用tail -f 试试,很快就出结果了。
下面就谈谈二者的区别:
1. tailf 总是从文件开头一点一点的读, 而tail -f 则是从文件尾部开始读
2. tailf check文件增长时,使用的是文件名, 用stat系统调用;而tail -f 则使用的是已打开的文件描述符; 注:tail 也可以做到类似跟踪文件名的效果; 但是tail总是使用fstat系统调用,而不是stat系统调用;结果就是:默认情况下,当tail的文件被偷偷删除时,tail是不知道的,而tailf是知道的。
关于stat & fstat
fstat与 stat() 函数相似,不同的是,它是作用于已打开的文件指针而不是文件名
关于 tail -F filename
-F filename 是跟踪文件名,当文件被删除或被重新创建是可以立即(伪立即)发现的。实现逻辑如下:
如果filename被打开了,不是每次都重新打开文件,而是用fstat检查文件是否变化,隔几次才使用open方法检查文件是否还在,如果成功打开了,则fstat检查一下是否依然是原来的那个文件,如果是,则直接关闭本次的文件描述符,依然使用原来的监视;如果不是,则开始监视新的文件,strace跟踪如下:
strace -F a
open("a", O_RDONLY|O_NONBLOCK) = 3 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 lseek(3, 0, SEEK_SET) = 0 nanosleep({1, 0}, NULL) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 read(3, "an", 8192) = 2 write(1, "an", 2a ) = 2 read(3, "", 8192) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({1, 0}, NULL) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({1, 0}, NULL) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({1, 0}, NULL) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({1, 0}, NULL) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({1, 0}, NULL) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 open("a", O_RDONLY|O_NONBLOCK) = 4 fstat(4, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 close(4) = 0 nanosleep({1, 0}, NULL) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({1, 0}, NULL) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({1, 0}, NULL) = 0
tail -retry 选项是干啥的
默认情况下, tail -f filename 当filename不存在时,则直接退出; 但是,如果使用-retry选项,则会不断尝试打开该文件,而不是直接退出,这在有时候是有用的
strace tailf
open("a", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2af8e0b98000 read(3, "an", 4096) = 2 read(3, "", 4096) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2af8e0b99000 write(1, "an", 2a ) = 2 stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({0, 250000000}, NULL) = 0 stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({0, 250000000}, NULL) = 0 stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({0, 250000000}, NULL) = 0 stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({0, 250000000}, NULL) = 0 stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({0, 250000000}, NULL) = 0 stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0 nanosleep({0, 250000000}, NULL) = 0
参考资料:
http://codingstandards.iteye.com/blog/832760
转载请注明:爱开源 » tailf and tail -f