Bash: grep including newline
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:]]/}" More in general
"Zoraya ter Beek, age 29, just died by assisted suicide in the Netherlands. She was physically healthy, but psychologically depressed. It's an abomination that an entire society would actively facilitate, even encourage, someone ending their own life because they had no hope. Th…"