我正在从连接到发送 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
如何避免缓冲?
编辑:凯尔琼斯建议 cat 正在缓冲其输出,但这似乎没有发生:
$ 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
当我思考时:我认为程序在写入终端时使用行缓冲,并在所有其他情况下使用“常规缓冲”。那么,为什么 cat 不进行更多缓冲呢?串口信号是EOF吗?那为什么cat没有被终止呢?
我的awk
是mawk 1.2。
答案1
我知道这是一个老问题,但是一句话可能会帮助那些来这里寻找的人:
cat /dev/ttyPSC9 | awk '{ print $0; system("")}'
system("")
确实有效,并且符合 POSIX 标准。非 posix 系统:要小心。
存在一个更具体的函数fflush()
可以执行相同的操作,但在旧版本的 awk 中不可用。
一条重要信息来自文档关于使用system("")
:
gawk 将 system() 函数的这种使用视为一种特殊情况,并且足够聪明,不会使用空命令运行 shell(或其他命令解释器)。因此,对于gawk来说,这个惯用语不仅有用,而且高效。
答案2
它可能是在 awk 中缓冲,而不是在 cat 中。在第一种情况下,awk 认为它是交互式的,因为它的输入和输出是 TTY(即使它们是不同的 TTY - 我猜 awk 没有检查这一点)。在第二个中,输入是管道,因此它以非交互方式运行。
您需要在 awk 程序中显式刷新。但这不是便携式的。
有关如何刷新输出的更多背景和详细信息,请阅读:http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html
答案3
老话题,但也许值得添加一个解决方案,以透明的方式改变流缓冲行为,而不需要一些魔法system("")
:-)
cat /dev/ttyPSC9 | stdbuf --output=L awk '{print $0}'
最近我自己用它来捕捉 D-Bus 事件。
gdbus monitor -y -d org.freedesktop.login1 | stdbuf -oL grep LockedHint