是否保证了tee打印到stdout的顺序?

时间:2010-06-29 18:04:11

标签: linux tee

您可以使用linux下的tee命令拆分管道,如下所示

printf "line1\nline2\nline3\n" | tee >(wc -l ) | (awk '{print "this is awk: "$0}')

产生输出

this is awk: line1
this is awk: line2
this is awk: line3
this is awk: 3

我的问题是,印刷顺序是否有保证?计算行数的tee拆分管道是否总是在末尾打印?有没有办法在开始时始终打印它?或者打印顺序tee从未得到保证?

3 个答案:

答案 0 :(得分:2)

它不是由发球台定义的,但是正如Daenyth所说,直到发球台传球数据才会完成wc - 所以通常也会将球传到awk上。在这种情况下,让awk进行计数可能会更好。

echo -ne {one,two,three,four}\\n | \
awk '{print "awk processing line " NR ": "$0} END {print "Awk saw " NR " lines"}'

缺点是它不会知道数字,直到它完成(知道它需要缓冲数据)。在您的示例中,tee和wc都将stdout连接到同一个管道(stdin for awk),但顺序未定义。 cat(以及大多数其他管道工具)可用于按已知顺序组装文件。

可以使用更先进的管道技术,例如bash coprocesses(coproc)或命名管道(mkfifo或mknod p)。后者在文件系统中为您提供名称,可以将其传递给其他进程,但您必须清理它们并避免发生冲突。 tempfile或$$可能对此有用。管道不用于缓冲数据,因为它们通常具有有限的大小并且将简单地阻止写入。

管道是错误解决方案的示例:

mkfifo wcin wcout
wc -l < wcin > wcout &
yes | dd count=1 bs=8M | tee wcin | cat -n wcout - | head

这里的问题是,tee会在试图向cat写东西时陷入困境,而cat希望先用wcout完成。从发球台到猫发球管的数据太多了。

关于dmckee答案的编辑: 是的,订单可能是可重复的,但不能保证。这是规模,调度和缓冲区大小的问题。在这个GNU / Linux框中,该示例在几千行后开始分解:

seq -f line%g 20000 | tee >(awk '{print "*" $0 "*"}' ) | \
(awk '{print "this is awk: "$0}') | less
this is awk: line2397
this is awk: line2398
this is awk: line2*line1*
this is awk: *line2*
this is awk: *line3*

答案 1 :(得分:1)

我怀疑在这种情况下,wc正在等待EOF,所以它不会返回(或打印输出),直到第一个命令完成发送输入,而awk逐行,所以将始终首先打印。我不知道在发送到其他进程时是否定义了它。

为什么不在打印线条之前让awk计算线条?

答案 2 :(得分:0)

我认为你不能指望它。 wc在这里运行,因此没有同步。我的试运行表明它可能是(至少在bash中)。作为Daenyth explains,这个特殊情况很特殊,但请使用grep -o line而不是wc来尝试,看看你得到了什么。

那就是说,在我的MacBoox上,我得到了:

$ printf "line1\nline2\nline3\nline4\nline5\n" | tee >(grep -o line ) | (awk '{print "this is awk: "$0}')
this is awk: line1
this is awk: line2
this is awk: line3
this is awk: line4
this is awk: line5
this is awk: line
this is awk: line
this is awk: line
this is awk: line
this is awk: line

非常一致。我必须非常仔细地阅读bash手册页。

类似地:

$ printf "line1\nline2\nline3\nline4\nline5\n" | tee >(awk '{print "*" $0 "*"}' ) | (awk '{print "this is awk: "$0}')
this is awk: line1
this is awk: line2
this is awk: line3
this is awk: line4
this is awk: line5
this is awk: *line1*
this is awk: *line2*
this is awk: *line3*
this is awk: *line4*
this is awk: *line5*

...每次和

$ printf "line1\nline2\nline3\nline4\nline5\n" | tee >(awk '{print "*" $0 "*"}' ) | (grep line)
line1
line2
line3
line4
line5
*line1*
*line2*
*line3*
*line4*
*line5*