【发布时间】:2018-11-25 08:23:41
【问题描述】:
当awk 通过管道处理/dev/stdin 时,有没有办法让awk 交互。
想象一下,我有一个不断生成数据的程序。示例:
$ od -vAn -tu2 -w2 < /dev/urandom
2357
60431
19223
...
这个数据正在由一个非常先进的awk 脚本通过管道处理:
$ od -vAn -tu2 -w2 < /dev/urandom | awk '{print}'
问题:是否有可能使这个awk 程序具有交互性:
- 程序连续打印输出
- 当按下单个键时(例如
z),它开始为从管道中读取的每一行只输出0。 - 当再次按键时,它继续输出原始数据,显然跳过了它打印为
0的已经处理过的记录。
问题:
/dev/stdin(也称为-)已经在使用中,所以键盘交互需要用/dev/tty接还是有别的办法?-
getline key < "/dev/tty"一直等待,直到遇到RS,所以在默认情况下,您需要按两个键(z 和 Enter):$ awk 'BEGIN{ getline key < "/dev/tty"; print key}'这是可以接受的,但我更喜欢单键。
那么,是否可以在本地设置
RS以使getline读取单个字符?这样我们就可以在本地修改RS并在getline之后重置它。另一种方法可能是使用 shell 函数read。但是bash和zsh不兼容。 -
getline等待输入直到时间结束。所以它基本上停止了管道的处理。有一个gawkextention 允许您设置超时,但这仅在gawk 4.2之后可用。所以我相信这可能会奏效:awk '{print p ? 0 : $0 } { PROCINFO["/dev/tty", "READ_TIMEOUT"]=1; while (getline key < "/dev/tty") p=key=="z"?!p:p }但是,我无法访问
gawk 4.2(更新:这不起作用)
请求:
- 我更喜欢完全符合 POSIX 的版本,它是或完全是 awk 或使用符合 POSIX 的系统调用
如果无法做到这一点,可以使用 3.1.7 之前的 gawk 扩展和独立于 shell 的系统调用。- 作为最后的手段,我会接受任何 shell-awk 构造,它可以在仅由
awk连续读取数据的单一条件下实现这一点(所以我在这里考虑使用多个管道)。
【问题讨论】:
-
你可以在你的while循环中运行一个外部脚本来用不可靠的bash替换getline的东西,
-
这至少会非常棘手,并且接近“不可能使用 awk”。您使用 Gawk 4.2 的超时解决方案可能会将正常流速率限制为每个超时周期一个输出数。我没有检查超时的计时单位,但你没有提到毫秒(或微秒或纳秒),所以它可能是“整数秒”。在 C 程序中,您会安排监视
/dev/stdin和/dev/tty的“可用字符”,并在可用时打印标准输入(或零),但在/dev/tty有可用数据的情况下,你会读的。 -
@LuisMuñoz
read的替代品可能是这个漂亮的技巧:$ stty cbreak -echo; KEY=$(dd if=/dev/tty bs=1 count=1 2>/dev/null); stty -cbreak echo(来源 here) -
对不起,我刚看到这个。我认为在 awk 中没有任何好的方法可以做到这一点。使用 gawk,您可能会执行一些操作,例如将
PROCINFO["-", "READ_TIMEOUT"]设置为一个小值,然后在处理每一行实际输入后从 stdin 获取行,但我怀疑这并不像说的那么容易,并且超时的可能粒度可能在这种情况下太高而不能真正有用。