使用getline
“功能”。它设置$0
为整个记录并以通常的方式$1
通过:$NF
$ awk '/test/ {
> while (("ping -c 2 google.com") | getline > 0) {
> printf("$1 = %s, $2 = %s\n", $1, $2);
> }
> }'
abc
test
$1 = PING, $2 = google.com
$1 = 64, $2 = bytes
$1 = 64, $2 = bytes
$1 = , $2 =
$1 = ---, $2 = google.com
$1 = 2, $2 = packets
$1 = round-trip, $2 = min/avg/max/stddev
xyz
$
编辑:在周围添加括号(cmd | getline)
(没有它们对我有用,但我猜一些 awk 变体需要它?)。
编辑 2:显然,“getline 周围的括号”来自GNU awk 手册中提到的一个完全不同的问题:
根据 POSIX,'表达式 | 如果表达式包含除 '$' 以外的未加括号的运算符,则 getline' 不明确——例如,'"echo " "date" | getline' 是模棱两可的,因为连接运算符没有括起来。你应该把它写成 '("echo " "date") | getline' 如果您希望您的程序可移植到所有 awk 实现。
在这种情况下,管道之前的表达式是单个字符串,因此没有歧义。我将括号移到了更复杂的表达式所需的位置。
此外,最好在循环退出close()
后调用命令。while
如果有另一行匹配test
,awk 将假定应该进一步阅读现有的子命令,除非它已被close()
d。由于命令匹配是通过字符串进行的,因此将其存储在一个变量中并将该变量用作close
. 例如:
awk '/^test / {
cmd = sprintf("ping -c %d %s", $2, $3)
while (cmd | getline > 0) print
close(cmd)
}'
(一种没有分号的变体,有些人不喜欢:-)),当喂食时:
test 1 google.com
产生:
PING google.com (74.125.225.161): 56 data bytes
64 bytes from 74.125.225.161: icmp_seq=0 ttl=56 time=22.898 ms
--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 22.898/22.898/22.898/0.000 ms
附录(在网上四处寻找,我发现这没有我想象的那么明显):注意这种“裸” getline
,因为它取代了“当前行”,导致任何剩余的模式和动作规则在脚本中触发新行内容。例如,在上述之后,$0
以 开头round-trip min/av
,因此表单的后续规则/^round/
将匹配,即使触发“ping”的输入行是test 1 google.com
。如果这不是最后一条规则,则向其添加next
指令可能是合适的。(在一个复杂的脚本中,我会将它放在每个getline
-ing 动作中,即使是最后一个,以防最后一条规则被移动,或者添加更多规则。)