一般我们使用tail -f来跟踪文件变化(或tail -F来对付轮转日志)。
但是在tail加上管道(例如tail -f | xxcmd )后,会发现输出可能有延时,
就是说,日志文件变化了,但管道命令并没有及时输出结果。要等到日志
变化达到一定量时才输出。
发生这种现象,就是因为IO缓冲机制造成的。
缓冲是一种有效提高IO效率的方法,把频繁的读写请求积累到一定程度后再
一次性的与IO设备交互操作。
IO缓冲有3种,无缓冲,行缓冲,和全缓冲。
无缓冲,就是不使用缓冲机制。面向字节的设备?(stderr)
行缓冲,缓冲,直到遇到换行符。一般用于终端设备。
全缓冲,缓冲,直到buffer满。一般用于块设备。
在终端窗口中执行tail命令,是面向终端设备的,会使用行缓冲,
所以日志中每写入一行,立刻就会输出。
当使用管道时,会变为使用全缓冲,这样一来,就要等到日志中
写入的字节数填满buffer后才会输出。
tail命令是如何判断,如何转换缓冲方式的,还没有来的及研究,
根据下面的实验现象,
tail -f加grep或sed,没有问题。但再加一层管道,就有问题。
tail -f加awk,有问题。
先记录一下几种解决方法。
一,使用stdbuf命令。它是coreutils包中的命令,一般系统都已安装。
它可以修改命令的缓冲方式。
例如 stdbuf -oL tail 就把tail的输出设置为行缓冲。
但是,有些命令,在命令中自己会设置缓冲方式,这就会覆盖stdbuf的设置。
还有一些命令是不使用流(stream)的(像cat和dd),stdbuf对他们无效。
二,把tail的标准输出重定向到标准错误上,并把标准错误也给管道。
因为stderr是无缓冲的。
例如 tail -f >&2 |& awk
实验结果:
a.log是另一个进程每秒写入的。
-
$ tail -fn0 a.log
-
2016/06/17 22:52:08
-
^C
-
$ tail -fn0 a.log |grep .
-
2016/06/17 22:52:12
-
^C
-
$ tail -fn0 a.log |grep .|grep .
-
^C
-
$ stdbuf -oL tail -fn0 a.log |grep .|grep .
-
^C
-
$ stdbuf -oL tail -fn0 a.log |stdbuf -oL grep .|grep .
-
2016/06/17 22:52:34
-
2016/06/17 22:52:35
-
^C
-
$ tail -fn0 a.log |stdbuf -oL grep .|grep .
-
2016/06/17 22:53:01
-
2016/06/17 22:53:02
-
2016/06/17 22:53:03
-
^C
-
$ tail -fn0 a.log |grep .|grep .
-
^C
-
$ tail -fn0 a.log |grep .|stdbuf -oL grep .
-
^C
-
$ tail -fn0 a.log >&2 |& grep .|grep .
-
2016/06/17 22:53:45
-
2016/06/17 22:53:46
-
^C
-
$ tail -fn0 a.log|awk '{print}'
-
^C
另外补充一点,
当我们使用协程时,一定要注意使用行缓冲,不然可能造成死锁。
阅读(4746) | 评论(0) | 转发(0) |