Trying to regex everything between two braces { }. Similar problem toRegex to match any character including newline - Vi & Vim, but I don't understand the solution provided.
Using:
nft list table inet filterReturns this:
table inet filter { set ipaddr { type ipv4_addr flags timeout elements = { 192.168.1.102, 192.168.1.119, 192.168.1.133, 192.168.1.134 } }
}I would like to use regex to get everything inside the elements such as:
192.168.1.102,192.168.1.119,192.168.1.133,192.168.1.134 I thought I could use grep, but whatever works will be great.
4 Answers
The information in the link is specific to vi/vim regex and is not directly applicable to grep.
Probably the equivalent in grep is to use perl compatible regular expressions (PCRE), with the s modifier that tells the regex engine to include newline in the . "any character" set (normally, . means any character except newline).
So for example with pcregrep using the Multiline flag:
$ pcregrep -Mo '(?s)elements = {.*?}' yourexample
elements = { 192.168.1.102, 192.168.1.119, 192.168.1.133, 192.168.1.134 }You can force something similar in regular GNU grep by using the -z flag as a proxy for -M:
grep -zPo '(?s)elements = {.*?}'If you want to format the matched text as well, I'd switch to perl proper ex.
$ perl -00nE 'say $1 =~ s/\n\s*/ /r if m/elements = {(.*?)}/s' yourdata 192.168.1.102, 192.168.1.119, 192.168.1.133, 192.168.1.134 Another solution would be:
nft list table inet filter | sed -zne 's/^.*elements = { //; s/ }.*$//; s/[ \n]\+/ /gp'Here, we are using:
- the
-zoption to treat the whole input as a single line. - the
-noption to suppress automatic printing of pattern space.
In the script part:
- The first script (
s/^.*elements = { //;) deletes the first part starting from beginning and going untilelements = {string on input. - The second script (
s/ }.*$//;) deletes the rest starting from}until the end of input. - The third script (
s/[ \n]\+/ /gp) replaces any multiple white space (new-line and space characters) with a single space characterglobally andprints the result.
Here is a sed solution (thanks @FedonKadifeli for the suggestion on shortening my initial command):
nft list table inet filter | sed -zn 's/.*elements = { \([0-9,\. \n]*\) }.*/\1/; s/\n//; s/ \+/ /p'We pipe the output of nft list table inet filter to a series of sed commands:
s/.*elements = { \([0-9,\. \n]*\) }.*/\1/selects anything between theelementsbrackets.s/\n//removes any newlines in the selection.s/ \+/ /preplaces multiple space with a single space.
From man sed:
-n, --quiet, --silent suppress automatic printing of pattern space
-z, --null-data separate lines by NUL charactersThe output is:
192.168.1.102, 192.168.1.119, 192.168.1.133, 192.168.1.134 0 You can use a bash regex statement.
$ [[ $(nft list table inet filter) =~ \ elements[\ =]+\{([^}]*) ]] && echo "${BASH_REMATCH[1]//[[:space:]]/}"