代码之家  ›  专栏  ›  技术社区  ›  ldog

tee打印到stdout的订单有保证吗?

  •  3
  • ldog  · 技术社区  · 16 年前

    可以使用 tee Linux下的命令如下

    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
    

    我的问题是,印刷订单有保证吗?威尔 球座 计算行数的拆分管道总是在末尾打印?有没有办法一开始就打印出来?还是印刷顺序 球座 从来没有保证过?

    3 回复  |  直到 16 年前
        1
  •  2
  •   Yann Vernier    16 年前

    它不是由tee定义的,但是正如daenyth所说,在tee完成传递数据之前,wc不会完成——所以通常tee也会在那时将数据传递给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连接到同一个管道(对于awk,stdin),但顺序未定义。cat(和大多数其他管道工具)可用于按已知顺序组装文件。

    可以使用更先进的管道技术,如bash corocesses(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。从tee到cat的管道数据太多了。

    编辑有关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*
    
        2
  •  1
  •   Daenyth    16 年前

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

    为什么不让awk在打印行之前计算行数呢?

        3
  •  0
  •   Community Mohan Dere    9 年前

    我觉得你不能指望。这个 wc 这里运行在单独的进程中,因此没有同步。 我的试运行表明它可能是(至少在bash中)。AS Daenyth explains ,这个特殊的情况是特殊的,但请尝试一下 grep -o line 而不是 厕所 看看你得到了什么。

    也就是说,在我的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*