Interacting with awk while processing a pipe
当通过管道处理
假设我有一个持续生成数据的程序。例子:
1 2 3 4 5 | $ od -vAn -tu2 -w2 < /dev/urandom 2357 60431 19223 ... |
这些数据由非常高级的
1 | $ od -vAn -tu2 -w2 < /dev/urandom | awk '{print}' |
问题:是否有可能使这个
- 程序连续打印输出
- 当按下一个键(如
z )时,它开始为从管道中读取的每一行只输出0 。 - 当再次按下该键时,它继续输出原始数据,明显跳过它打印为
0 的已处理记录。
问题:
/dev/stdin (也被称为- )已经在使用中,因此需要与/dev/tty 进行键盘交互,还是有其他方法?getline key <"/dev/tty" 等待,直到遇到RS 为止,因此在默认情况下,您需要按两个键(zabbkbd和enter):1$ awk 'BEGIN{ getline key <"/dev/tty"; print key}'这是可以接受的,但我更喜欢单按键。
那么,是否可以在本地设置
RS ,以便getline 读取单个字符?这样我们就可以在本地修改RS ,并在getline 之后重置它。另一种方法是使用shell函数read 。但它在bash 和zsh 之间是不相容的。getline 等待输入直到时间结束。所以它基本上停止了管道的处理。有一个gawk 扩展允许您设置超时,但这只在gawk 4.2 之后可用。因此我相信这可能有效:1
2
3
4awk '{print p ? 0 : $0 }
{ PROCINFO["/dev/tty","READ_TIMEOUT"]=1;
while (getline key <"/dev/tty") p=key=="z"?!p:p
}但是,我没有访问
gawk 4.2 的权限(更新:这不起作用)
请求:
经过一些搜索,我想出了一个bash脚本,允许这样做。其思想是在awk正在处理的管道中注入一个唯一的可识别字符串。原始程序
最后,看起来是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/usr/bin/env bash # make a fifo which we use to inject the output of data-stream # and the key press mkfifo foo # start the program in line-buffer mode, writing to FIFO # and run it in the background stdbuf -o L od -vAn -tu2 -w2 < /dev/urandom > foo & # run the awk program that processes the identified key-press # also run it in the background and insert a clear EXIT strategy awk '/key/{if ($2=="q") exit; else p=!p} !p{print} p{print 0}' foo & # handle the key pressing # if a key is pressed inject the string"key <key>" into the FIFO # use"q" to exit while true; do read -rsn1 key echo"key $key"> foo [[ $key =="q" ]] && exit done |
注:我忽略了密钥必须是
一些有用的帖子:
- 读取进程在写入进程之前终止时的Unix/Linux管道行为
- Shell脚本响应按键