我现在观察了几次A | B | C
可能不会导致立即输出,尽管A
不断产生输出。我不知道这怎么可能。根据我的理解,所有三个进程应该同时工作,将它们的输出放入下一个管道(或stdout),并在它们完成一步时从前一个管道中取出。
以下是我目前遇到的一个例子:
tcpflow -ec -i any port 8340 | tee second.flow | grep -i "\(</Manufacturer>\)\|\(</SerialNumber>\)" | awk -F'[<>]' '{print $3}'
应该发生什么:
我看一下tcp包的端口。如果出现问题,它应该是某种XML格式,我想从这些软件包中获取制造商和序列号。我还希望在文本文件&#34; second.flow&#34;中获得完整的,未修改的输出,以供日后参考。
会发生什么:
一切都符合要求,但不是每10秒钟输出一次(我确定每十秒钟就会得到这些输出!)我必须等待很长时间,然后立即打印很多。它就像其中一个工具吞噬了缓冲区中的所有内容,只有在缓冲区已满时才会打印出来。我不想要那个。我希望尽可能快地获得每一行。
如果我将tcpflow ...
替换为cat second.flow
,则会立即生效。有人可以描述一下发生了什么吗?如果显而易见,还有另一种方法可以达到相同的效果吗?
答案 0 :(得分:3)
一系列管道中的每一层都可能涉及缓冲;默认情况下,未指定stdout
缓冲行为的工具将在输出到终端时使用行缓冲,并在输出到其他任何位置时阻止缓冲(包括管道到另一个程序或文件)。在链式管道中,除了最后一个阶段之外的所有阶段都会看到它们的输出不会到达终端,并且会阻塞缓冲区。
因此,在您的情况下,tcpflow
可能会不断产生输出,如果它正在这样做,tee
应该几乎以相同的速率生成数据。但grep
将限制流向涓流,并且在涓流超过输出缓冲区大小之前不会产生输出。它已经执行了过滤并调用了fwrite
或puts
或printf
,但数据在将其发送到awk
之前等待足够的字节在其后面构建减少(昂贵的)系统调用的数量。
cat second.flow
立即生成输出,因为只要cat
完成输出,它就会退出,刷新并关闭进程中的stdout
,当每个步骤找到它时stdin
stdout
tcpflow
grep
1}}在EOF,它退出,刷新并关闭它的tcpflow
。 tee
没有退出,所以EOF和级联的级联没有发生。
对于某些程序,在一般情况下,您可以使用stdbuf
(或unbuffer
更改缓冲行为,但这不能进行行缓冲来平衡效率,并且存在管道问题输入)。如果程序使用内部缓冲,这仍然可能不起作用,但值得一试。
在你的特定情况下,因为它可能stdout
导致中断(通过仅产生一个粘在缓冲区中的涓流输出,其中tcpflow -ec -i any port 8340 | tee second.flow | grep -i --line-buffered "\(</Manufacturer>\)\|\(</SerialNumber>\)" | awk -F'[<>]' '{print $3}'
和grep
是生成一个torrent,并且awk连接到tcpflow
,因此默认情况下缓冲行),你只需将命令行调整为:
stdbuf
至少对于Linux's grep
(不确定switch是否是标准的),这使tee
明确地将其自己的输出缓冲更改为面向行的缓冲,这应该消除延迟。如果stdbuf
本身没有产生足够的输出来定期刷新(你暗示它确实存在,但你可能错了),你可以使用stdbuf
(但不是stdbuf -oL tcpflow -ec -i any port 8340 | tee second.flow | grep -i --line-buffered "\(</Manufacturer>\)\|\(</SerialNumber>\)" | awk -F'[<>]' '{print $3}'
,每个awk
手册页注释,手动更改其缓冲,因此stdout
不做任何事情)使它们行缓冲:
system("")
从评论更新:看起来有些print
块缓冲区打印到fflush()
,即使连接到终端也是如此。 For mawk
(the default on many Debian based distros), you can non-portably disable it by passing the -Winteractive
switch at invocation。或者,为了便于上班,您可以在awk
awk
之后拨打fflush()
。遗憾的是,显而易见的<target name="compile" depends="init,copy-non-java-files">
<javac srcdir="${src}" destdir="${build}" source="1.6">
<classpath>
<pathelement path="${java.class.path}/" />
<fileset dir="*\\eclipse\\plugins">
<include name="**/*.jar" />
</fileset>
<fileset dir="${lib}">
<include name="**/*.jar" />
</fileset>
</classpath>
</javac>
</target>
无法移植到较早的indexes
实现中,但如果您只关心现代df
,则只需使用axis=1
即可,并且大部分都是可移植的。< / p>
答案 1 :(得分:1)
管道中的每个应用程序都可以自己进行缓冲。您可能想看看是否可以减少tcpflow中的缓冲,因为其他命令是面向行的,并且不太可能成为缓冲问题的根源。我没有在tcpflow中看到缓冲区控制的任何特定选项,尽管 max_bytes 的-b
标志可能有助于您要使用的文本靠近流的前端的情况
您还可以尝试使用stdbuf from GNU coreutils修改tcpflow的缓冲。这可能有助于减少管道中的延迟,但手册页提供了以下警告:
注意:如果COMMAND调整其标准流的缓冲(例如'tee'),则会通过'stdbuf'覆盖相应的更改。另外一些过滤器(如'dd'和'cat'等)不使用I / O流,因此不受'stdbuf'设置的影响。
例如,以下可能减少tcpflow的输出缓冲:
stdbuf --output=0 tcpflow -ec -i any port 8340 # unbuffered output
stdbuf --output=L tcpflow -ec -i any port 8340 # line-buffered output
除非上述警告之一适用。您的里程可能会有所不同。