无法重定向剪切输出

无法重定向剪切输出

当我尝试重定向cut它的输出时,它似乎总是为空。如果不重定向它,输出将按预期显示在终端中。对于 OS X 10.10 和 Linux 4.1.6 来说也是如此。

这有效:

root@karla:~# nc 10.0.2.56 30003
[...] lots of lines [...]

这有效:

root@karla:~# nc 10.0.2.56 30003 | cat
[...] lots of lines [...]

这有效:

root@karla:~# nc 10.0.2.56 30003 | cut -d, -f 15,16
[...] lots of lines [...]

这不

root@karla:~# nc 10.0.2.56 30003 | cut -d, -f 15,16 | cat
[nothing]

又是这个

root@karla:~# cat messung1 | cut -d, -f15,16 | cat
[...] lots of lines [...]

这不仅限于cat之后cutgreptee并且使用标准重定向>也不起作用。

那里出了什么问题?

答案1

并不是没有输出,而是成块地输出。

与许多程序一样,当其输出不再是终端时,cut会缓冲其输出。也就是说,它仅在缓冲区已满时才写入数据。通常,YMMV 约为 4 或 8 KiB。

您可以通过比较轻松验证:

(echo foo; sleep 1; echo bar) | cut -c2-

和:

(echo foo; sleep 1; echo bar) | cut -c2- | cat

在第一种情况下,cut输出oo\n,然后ar\n一秒后输出,而在第二种情况下,oo\nar\n在一秒后切断输出,即当它看到输入结束并在退出时刷新其输出时。

在您的情况下,由于 stdin 是nc,因此当连接关闭时它只会看到其输入的结尾,因此它只会在积累了 4KiB 的数据要写入后才开始输出任何内容。

为了解决这个问题,可以采用多种方法。

  • 在 GNU 或 FreeBSD 系统上,您可以使用stdbuf可以调整某些命令的缓冲行为的实用程序(它并不适用于所有命令,因为它使用 LD_PRELOAD hack 来预先配置 stdio 缓冲行为)。

    ... | stdbuf -oL cut -d, -f15,16 | cat
    

    会告诉cut在其标准输出上进行基于行的缓冲。

  • 一些命令(例如 GNU)grep具有影响其缓冲的选项。 (--line-buffered对于 GNU 来说grep)。

  • 您可以使用伪 tty 包装器强制命令的标准输出为终端。然而,大多数这些解决方案都有一些缺点和限制。unbuffer expect例如,经常提到的解决此类问题的脚本有许多错误。

    效果还不错的一种是使用socatas 时:

    ... | socat -u 'exec:"cut -d, -f15,16",pty,raw' -
    
  • 您可以将文本实用程序替换为支持无缓冲输出的高级文本处理工具。

    • awk例如,GNU有一个fflush()函数来刷新其输出。所以你的cut -d, -f15,16可以写成:

      awk -F, -vOFS=, '{print $15,$16;fflush()}'
      
    • 如果您awk缺少该fflush()功能,您可以使用system("")它来代替。这通常是执行命令的命令。在这里,我们将执行一个空命令,但实际上使用它是为了awk在运行命令之前刷新其标准输出。

    • 或者你可以使用perl

      perl -F, -lane 'BEGIN{$,=",";$|=1} print @F[14..15]'
      

相关内容