为什么从管道读取时awk会做全缓冲


23

我正在从连接到发送nmea字符串的gps设备的串行端口读取。

一个简化的调用来说明我的观点:

  $ awk '{ print $0 }' /dev/ttyPSC9 
  GPGGA,073651.000,6310.1043,N,01436.1539,E,1,07,1.0,340.2,M,33.3,M,,0000*56
  $GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39
  $GPRMC,073651.000,A,6310.1043,N,01436.1539,E,0.42,163.42,070312,,,A*67
  GPGGA,073652.000,6310.1043,N,01436.1540,E,1,07,1.0,339.2,M,33.3,M,,0000*55
  $GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39

如果我改为尝试从管道读取,awk会将输入发送到stdout之前先对其进行缓冲。

$ cat /dev/ttyPSC9 | awk '{ print $0 }'
<long pause>
GPGGA,073651.000,6310.1043,N,01436.1539,E,1,07,1.0,340.2,M,33.3,M,,0000*56
$GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39
$GPRMC,073651.000,A,6310.1043,N,01436.1539,E,0.42,163.42,070312,,,A*67
GPGGA,073652.000,6310.1043,N,01436.1540,E,1,07,1.0,339.2,M,33.3,M,,0000*55
$GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39

如何避免缓冲?

编辑:凯尔·琼斯(Kyle Jones)建议,猫正在缓冲它的输出,但是这似乎没有发生:

$ strace cat /dev/ttyPSC9 | awk '{ print $0 }'
write(1, "2,"..., 2)                    = 2
read(3, "E"..., 4096)                   = 1
write(1, "E"..., 1)                     = 1
read(3, ",0"..., 4096)                  = 2

考虑一下:我认为程序在写入终端时使用行缓冲,而在所有其他情况下都使用“常规缓冲”。那么,为什么猫不多缓冲呢?串行端口发出EOF信号吗?那猫为什么不被终止呢?


1
BashFAQ 009可能有用。
jw013 2012年

@ jw013:感谢您的链接,它很好地总结了bash中缓冲的工作方式。
DanielNäslund2012年

Answers:


10

它可能会在awk中缓冲,而不是cat。在第一种情况下,awk认为它是交互式的,因为它的输入和输出是TTY(即使它们是不同的TTY,我猜awk不会检查它)。在第二个中,输入是管道,因此它是非交互式运行的。

您将需要显式刷新awk程序。但是,这不是便携式的。

有关如何刷新输出的更多背景和详细信息,请阅读:http : //www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html


6
感谢您的解释。awk -W interactive '{print $0}'似乎可以解决问题。该'W interactive选项在我的awk版本(mawk 1.2)上可用,但我不知道是否为标准选项。
DanielNäslund2012年

1
@dannas -W不在的POSIX标准中awk。如果您需要最大的便携性,我不确定该怎么办。
jw013 2012年

我接受这个答案,因为它解释了为什么我的示例中awk进行全缓冲而不是行缓冲-它检查输入和输出是否都是tty。我只认为它将检查输出。
DanielNäslund2012年

@ jw013:感谢您查找标准。对我来说,我只是想了解awk为什么要进行全缓冲,我想我现在就这样做。
DanielNäslund2012年

@dannas我可以确认-W interactive至少在awk的Ubuntu 12.04(可能是较新的)发行版中受支持,该发行版是mawk。
詹森·C

37

我知道这是一个古老的问题,但是单线可能会帮助那些来这里搜索的人:

cat /dev/ttyPSC9 | awk '{ print $0; system("")}'

system("")绝招,并且符合POSIX。非posix系统:当心。

有一个更特定的功能fflush()可以执行相同的功能,但是在旧版本的awk中不可用。

文档中有关以下方面的重要信息system("")

gawk将对system()函数的这种使用视为一种特殊情况,并且非常聪明,以至于无法使用empty命令运行shell(或其他命令解释器)。因此,对于gawk来说,这个成语不仅有用,而且非常有效。


这对我
有用

3
awk既不fflush()也不做任何事情system("")。我gawk很荣幸。
KrzysztofJabłoński17年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.