通过管道处理awk
时,有一种方法可以使/dev/stdin
互动。
想象一下,我有一个不断生成数据的程序。示例:
$ 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
等待输入直到时间结束。所以它基本上停止了管道的处理。有gawk
extention允许您设置超时,但这仅在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
请求:
awk
连续读取数据的单一条件下实现这一点(所以我在这里想多个管道) 答案 0 :(得分:1)
经过一些搜索,我想出了一个Bash脚本,可以执行此操作。这个想法是将唯一可识别字符串注入awk正在处理的管道中。原始程序od
和bash脚本都写入管道。为了不破坏这些数据,我使用stdbuf
运行行缓冲的程序od
。此外,由于是处理按键的bash脚本,因此原始程序和awk脚本都必须在后台运行。因此,需要采取干净的退出策略。按下键q
时,awk将退出,而终止awk时,od
将自动终止。
最后,它看起来像这样:
#!/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
注意:我忽略了密钥必须为z
一些有用的帖子: