如何在非固定位置使用 grep 或 awk 字符串
How to grep or awk string in non fixed position
我没有找到类似的解决方案,除了解析多个参数,它本身就是一个完整的脚本。
我需要从脚本的 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
}
}
我需要捕获“handle #”,在本例中是 223,前后没有任何空格
通常我会这样做:
InsNo=$(nft -n -a list chain inet fw4 forward|grep -m 1 "192.168.0.0"|awk '{print }')
仅当存在固定数量的字段时才有效。我也试过了
InsNo=$(nft -n -a list chain inet fw4 forward|grep -m 1 "192.168.0.0"|awk -F'handle ' '{print }')
如果句柄号后没有更多参数,则该方法有效。但是我想知道有没有更靠谱的方法,获取这个数字,前后不带空格。
您可以检查该行是否包含 192.168.0.0
,如果句柄部分可以在该行的任何位置,则进行匹配。
在第一次匹配后,使用 substr 删除前导 handle
并退出程序。
例如,如果示例数据在file
awk '
/192\.168\.0\.0/ && match([=10=], /handle [0-9]+/) {
print substr([=10=], RSTART+7)
exit
}' file
输出
223
如果 handle 部分总是在 ip 之后,您也可以使用 gnu awk
和捕获组:
awk '
match([=12=], /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
}
}')
awk
解决方案是您最简单的选择(以及您询问的内容),但是通过匹配 handle
和连续的数字。只是一个额外的选择,因为......为什么不呢。
nft -n -a list chain inet fw4 forward |
sed -En '/192\.168\.0\.0/s/.*# +handle +([0-9]+).*//p'
最终的解决方案是“只有第一场比赛”,结果是这样的:
nft -n -a list chain inet fw4 forward |
sed -En '/192\.168\.0\.0/{s/.*# +handle +([0-9]+).*//p; q}
()
parathesis 是一个捕获组,稍后由 </code> 恢复,即返回其中的匹配项。 <code>[0-9]
匹配任何数字,随后的 +
匹配其中的“一个或多个” = 任意数量的连续数字。 Th p
将行打印到标准输出。它是必需的,因为我们使用 -n 标志抑制所有行。要只打印一个匹配项,只需将替代项封装在 {}
大括号中并添加 q
以退出。
我没有找到类似的解决方案,除了解析多个参数,它本身就是一个完整的脚本。
我需要从脚本的 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
}
}
我需要捕获“handle #”,在本例中是 223,前后没有任何空格 通常我会这样做:
InsNo=$(nft -n -a list chain inet fw4 forward|grep -m 1 "192.168.0.0"|awk '{print }')
仅当存在固定数量的字段时才有效。我也试过了
InsNo=$(nft -n -a list chain inet fw4 forward|grep -m 1 "192.168.0.0"|awk -F'handle ' '{print }')
如果句柄号后没有更多参数,则该方法有效。但是我想知道有没有更靠谱的方法,获取这个数字,前后不带空格。
您可以检查该行是否包含 192.168.0.0
,如果句柄部分可以在该行的任何位置,则进行匹配。
在第一次匹配后,使用 substr 删除前导 handle
并退出程序。
例如,如果示例数据在file
awk '
/192\.168\.0\.0/ && match([=10=], /handle [0-9]+/) {
print substr([=10=], RSTART+7)
exit
}' file
输出
223
如果 handle 部分总是在 ip 之后,您也可以使用 gnu awk
和捕获组:
awk '
match([=12=], /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
}
}')
awk
解决方案是您最简单的选择(以及您询问的内容),但是通过匹配 handle
和连续的数字。只是一个额外的选择,因为......为什么不呢。
nft -n -a list chain inet fw4 forward |
sed -En '/192\.168\.0\.0/s/.*# +handle +([0-9]+).*//p'
最终的解决方案是“只有第一场比赛”,结果是这样的:
nft -n -a list chain inet fw4 forward |
sed -En '/192\.168\.0\.0/{s/.*# +handle +([0-9]+).*//p; q}
()
parathesis 是一个捕获组,稍后由 </code> 恢复,即返回其中的匹配项。 <code>[0-9]
匹配任何数字,随后的 +
匹配其中的“一个或多个” = 任意数量的连续数字。 Th p
将行打印到标准输出。它是必需的,因为我们使用 -n 标志抑制所有行。要只打印一个匹配项,只需将替代项封装在 {}
大括号中并添加 q
以退出。