当我在bash中运行以下命令时,它会等到程序完成后再刷新所有输出。如果我移除管道,则立即打印每一行。
{ for i in `seq 3` ; do echo $i ; sleep 1 ; done ; } \
| perl -p -e 's,(.*ERROR.*),\e[01;31m\1\e[00m,g' \
| perl -p -e 's,(.*WARNING.*),\e[01;33m\1\e[00m,g' \
| perl -p -e 's,(.*TCPEchoTest.*),\e[01;30m\1\e[00m,g' \
| perl -p -e 's,(.*enters.*),\e[00;33m\1\e[00m,g'
如何使用管道并且仍然立即打印每条线?
答案 0 :(得分:4)
管道通常具有默认的4kB缓冲区,其中输出可以保持直到程序完成执行。
尝试使用stdbuf
实用程序禁用此缓冲区,以便立即输出文本:
stdbuf -i0 -o0 -e0 command | perl ...
答案 1 :(得分:4)
perl正在执行缓冲,因此perl命令是您需要更改以将其关闭的命令。
在每个perl命令中设置$|
变量,如下所示:
{ for i in `seq 3` ; do echo $i ; sleep 1 ; done ; } \
| perl -p -e 'BEGIN{$|=1}s,(.*ERROR.*),\e[01;31m\1\e[00m,g' \
| perl -p -e 'BEGIN{$|=1}s,(.*WARNING.*),\e[01;33m\1\e[00m,g' \
| perl -p -e 'BEGIN{$|=1}s,(.*TCPEchoTest.*),\e[01;30m\1\e[00m,g' \
| perl -p -e 'BEGIN{$|=1}s,(.*enters.*),\e[00;33m\1\e[00m,g'
BEGIN
块导致分配在读取任何输入之前发生一次,而不是在使用-p
读取每一行之后执行此操作。
答案 2 :(得分:3)
首先,使用colortail
,colorize
或ccze
等日志着色工具。
在更一般的情况下,问题是当stdout不是终端时,libc将通过缓冲自动优化吞吐量。这可以显着减少非交互式作业的系统调用次数。对于此以及更多内容,请比较interactive and non-interactive output。
当进程认为它不是交互式的时,虽然你知道它是,但有几种方法可以说服它在每次逻辑写入后刷新缓冲区:
Wumpus的方法,解释改变缓冲的说明:
$|=1
或Perl中的等效STDOUT->autoflush(1)
fflush()
sys.stdout.flush()
计划特定设置:
-u
和GNU sed --line-buffered
打开终端的PTY,使stdout成为TTY并解决问题:
script -q /dev/null yourcommand
unbuffer
的expect package
最后$LD_PRELOAD
hacks将选项注入进程的C运行时(整齐地包装在GNU coreutils stdbuf
中,由Vilhelm建议)
答案 3 :(得分:2)
你可以用重复的-e选项连接几行perl代码(一定要用;
结束它们 - 它们串在一起形成一个程序)。你可以使用$|=1
使管道“热”。有关详细信息,请参阅perl manual on $|
(页面下方2/3,搜索OUTPUT_AUTOFLUSH)。
{ for i in `seq 3` ; do echo $i ; sleep 1 ; done ; } \
| perl -p -e 'BEGIN{$|=1};' \
-e 's,(.*ERROR.*),\e[01;31m\1\e[00m,g;' \
-e 's,(.*WARNING.*),\e[01;33m\1\e[00m,g;' \
-e 's,(.*TCPEchoTest.*),\e[01;30m\1\e[00m,g;' \
-e 's,(.*enters.*),\e[00;33m\1\e[00m,g;'
打印1,2,3,每个数字之间有一秒钟。实际上,当perl输出到终端时,不需要BEGIN行。但是如果你继续管道到另一个程序,你想要它。