我是Stack Overflow处女(好吧,直到现在)所以请和我一起露出......
我在这里找到了一些很好的帮助,关于hoe从awk中调用外部命令并将结果存储在变量中。我无法找到的是如何让awk对普通输入文本文件的结果采取行动。
我使用awk来解析一个小的HTML文件(正在运行的Tahoe LAFS节点的状态页面),以便找到列出的一些IP地址。在每个IP地址上,我运行特定端口的nmap扫描以查看它是否打开(是的,这将成为自动化的Tahoe LAFS网格监视器)。使用if语句我可以从nmap中选出包含端口状态(打开/过滤/关闭)作为其第二个字段(通常为“8098 / TCP open unknown”)的输出行。我想剥离字段1和3的行,只保留字段2,但是,$ 2当然是指我用作awk脚本输入的HTML文件中的字段。我尝试了一个用户定义的函数,它只返回2美元,但这也引用了输入HTML文件中的字段。
有没有办法在awk脚本中引用内部创建的变量中的字段?像awk脚本中的嵌套awk命令?
提前谢谢!
此致 安德斯
答案 0 :(得分:3)
使用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 manuals中提到的一个完全不同的问题:
根据POSIX,'表达式|如果表达式包含除“$”之外的未加括号的运算符,则getline'是不明确的 - 例如,'“echo”“date”| getline'是不明确的,因为连接运算符没有括号。你应该把它写成'(“echo”“date”)| getline'如果你希望你的程序可以移植到所有awk实现。
在这种情况下,管道前的表达式是单个字符串,因此没有歧义。我将括号移到了更复杂表达所需的位置。
此外,在close()
循环退出后,在命令上调用while
是个好主意。如果有另一行匹配test
,awk将假定应该进一步读取现有的子命令,除非它已经close()
d。由于命令匹配是通过字符串进行的,所以更好,而不是将管道到getline的左侧括起来,将其存储在变量中,并将该变量用作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”的输入行为{{1} }。如果这不是最后一条规则,则可能需要向其添加test 1 google.com
指令。 (在一个复杂的脚本中,我将它放在每个next
动作中,即使是最后一个动作,以防移动最后一条规则,或者添加更多规则。)
答案 1 :(得分:0)
由于我的最终awk脚本的相关部分太大而无法作为评论,我将作为答案发布。 stripInputRecord,getIpNumber和getPortNumber函数只是从HTML代码中挑选出有用的部分。
/address/ {
ip = stripInputRecord( $0 );
ip = getIpNumber( ip );
port[na] = stripInputRecord( $0 );
port[na] = getPortNumber( port[na] );
if (!(ip~"N/A")) {
if (ip~/loopback/) {
ip="127.0.0.1";
port[na]=stdp;
}
cmd="nmap -PN -p "stdp" "ip
cmd2="nmap -PN -p " port[na] " " ip
while ((cmd | getline)==1) {
if ($0~stdp) {
stdportstatus[na] = $2
}
}
while ((cmd2 | getline)==1) {
if ($0~port[na]) {
otherportstatus[na] = $2
}
}
}
close(cmd)
close(cmd2)
if ($0~/N\/A/) {
stdportstatus[na] = "-";
otherportstatus[na] = "-";
}
na++;
}
谢谢大家(特别是torek!)