Home > OS >  How to grep or awk string in non fixed position
How to grep or awk string in non fixed position

Time:02-02

I didn't find similar solution, apart from parsing multiple arguments which is a whole script by it self.
I need to get handle # from nftables for the script, and having problems because it is not always located on the same position. With Iptables it was line number which was always listed on the first field so was very easy to capture insert position. when I do: nft -n -a list chain inet fw4 forward output would be something like this:

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
    }
}

I need to capture "handle #", which in this case is 223 without any spaces before or after normally I would do:

InsNo=$(nft -n -a list chain inet fw4 forward|grep -m 1 "192.168.0.0"|awk '{print $10}')

which works only when fixed number of fields are present. I tried also

InsNo=$(nft -n -a list chain inet fw4 forward|grep -m 1 "192.168.0.0"|awk -F'handle ' '{print $2}')

which works if no more arguments are present after handle number. But I'd like to know if there is any more reliable method, in getting this number, also without spaces before or after.

CodePudding user response:

You could check if the line contains 192.168.0.0 and then get a match if the handle part can be anywhere in the line.

After the first match remove the leading handle using substr and exit the program.

For example, if the example data is in file

awk '
/192\.168\.0\.0/ && match($0, /handle [0-9] /) {
    print substr($0, RSTART 7)
    exit  
}' file

Output

223

If for exampe the handle part always comes after the ip, you might also use gnu awk with a capture group:

awk '
match($0, /192\.168\.0\.0.*handle ([0-9] )/, a) {
    print a[1]
    exit  
}' file

CodePudding user response:

The piece of information you're apparently missing is that awk has a variable named NF for the number of fields. And also that you should use the -F grep option to interpret the 192.168.0.0 pattern as fixed string, not regular expression.

InsNo=$(nft -n -a list chain inet fw4 forward | grep -F -m 1 "192.168.0.0" |
  awk '{print $NF}')

But piping grep in awk is usually a waste:

InsNo=$(nft -n -a list chain inet fw4 forward |
  awk '/192\.168\.0\.0/ {print $NF}')
  •  Tags:  
  • Related