当我尝试重定向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
之后cut
。grep
,tee
并且使用标准重定向>
也不起作用。
那里出了什么问题?
答案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
例如,经常提到的解决此类问题的脚本有许多错误。效果还不错的一种是使用
socat
as 时:... | 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]'