我没有找到类似的解决方案,除了解析多个参数,它本身就是一个完整的脚本。
我需要从脚本的 nftables 获取句柄 #,并且遇到了问题,因为它并不总是位于同一位置。 使用Iptables,它是行号,总是列在第一个字段中,因此很容易捕获插入位置。 当我这样做时:nft -n -a list chain inet fw4 forward
输出将是这样的:
table inet fw4 {
chain forward { # handle 2
type filter hook forward priority 0; policy drop;
ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 accept # handle 223
ct state 0x2,0x4 accept comment "!fw4: Allow forwarded established and related flows" # handle 179
iifname "br-lan" jump forward_lan comment "!fw4: Handle lan IPv4/IPv6 forward traffic" # handle 180
iifname "eth0.2" jump forward_wan comment "!fw4: Handle wan IPv4/IPv6 forward traffic" # handle 181
jump handle_reject # handle 182
}
}
我需要捕获"句柄#",在本例中为 223,前后没有任何空格 通常我会这样做:
InsNo=$(nft -n -a list chain inet fw4 forward|grep -m 1 "192.168.0.0"|awk '{print $10}')
仅当存在固定数量的字段时才有效。 我也试过
InsNo=$(nft -n -a list chain inet fw4 forward|grep -m 1 "192.168.0.0"|awk -F'handle ' '{print $2}')
如果句柄编号后没有更多参数,则有效。 但是我想知道是否有更可靠的方法,在获取这个数字时,前后也没有空格。
awk
解决方案是你在这里最简单的选择(以及你问到的),但可以通过匹配handle
和连续数字来编写sed
可能"更安全"的版本。只是一个额外的选择,因为...为什么不呢。
nft -n -a list chain inet fw4 forward |
sed -En '/192.168.0.0/s/.*# +handle +([0-9]+).*/1/p'
最终解决方案是"只有第一场比赛",结果如下:
nft -n -a list chain inet fw4 forward |
sed -En '/192.168.0.0/{s/.*# +handle +([0-9]+).*/1/p; q}
()
参数是一个捕获组,稍后由1
恢复,即返回匹配项。[0-9]
匹配任何数字,以下+
匹配"一个或多个"= 任意数量的连续数字。p
打印线到标准输出。它是必需的,因为我们使用 -n 标志抑制所有行。要只打印一个匹配项,只需将替换项封装在{}
大括号中,并添加q
退出。
您可以检查该行是否包含192.168.0.0
,然后如果手柄部分可以在该行中的任何位置,则获得匹配项。
在第一次匹配后,使用 substr 删除前导handle
并退出程序。
例如,如果示例数据处于file
awk '
/192.168.0.0/ && match($0, /handle [0-9]+/) {
print substr($0, RSTART+7)
exit
}' file
输出
223
如果对于 exampe,句柄部分总是在 ip 之后,您还可以将gnu awk
与捕获组一起使用:
awk '
match($0, /192.168.0.0.*handle ([0-9]+)/, a) {
print a[1]
exit
}' file
您显然缺少的信息是awk
有一个名为NF
的变量表示字段数。而且,您应该使用-F
grep 选项将192.168.0.0
模式解释为固定字符串,而不是正则表达式。
InsNo=$(nft -n -a list chain inet fw4 forward | grep -F -m 1 "192.168.0.0" |
awk '{print $NF}')
但是在awk
中配管grep
通常是一种浪费:
InsNo=$(nft -n -a list chain inet fw4 forward |
awk '/192.168.0.0/ {print $NF}')
如果您感兴趣的字段并不总是最后一行,而是始终遵循字段#
和handle
,并且始终是十进制数,我们可以更准确一点:
InsNo=$(nft -n -a list chain inet fw4 forward |
awk '/192.168.0.0/ {
for(i=1; i<=NF-2; i++)
if($i=="#" && $(i+1)=="handle" && $(i+2)~/^[0-9]+$/)
print $(i+2)
}')
最后,如果您只想要第一个匹配项,只需在print
之后添加一个exit
语句:
InsNo=$(nft -n -a list chain inet fw4 forward |
awk '/192.168.0.0/ {
for(i=1; i<=NF-2; i++)
if($i=="#" && $(i+1)=="handle" && $(i+2)~/^[0-9]+$/) {
print $(i+2); exit
}
}')