awk Extract Text Nth Occurrence Square Brackets (Containing Line Break In File Text)

Viewed 176

I have 0.txt and 1.txt files. In the 0.txt file the content is as shown below:

[{A,B,C},{D,E,F}][{G,H,I}]

The contents of the 1.txt file is as shown below:

[{A,B,C},{D,E,F}]
[{G,H,I}]

That is, the difference between 0.txt and 1.txt is that in the 1.txt file there is a line break.

What I desire is to be able to extract all the text between '[' and ']' in your NTH OCCURRENCE using awk -F'[][]' -v n=2 '{ print $(2*n) }' 1.txt > 2.txt (Extract the text between the nth occurrence of square brackets), this for text formatting shown in 1.txt file.

So my wishes corresponding to n=2 would be 2.txt as shown below:

{G,H,I}

To do so, at first, I have been able to do this just for text formatting when there is no line break as shown at 0.txt.

I need to know how to extract the text between '[' and ']' when there is line break as shown at 1.txt.

The output of awk -F'[][]' -v n=2 '{ print $(2*n) }' 1.txt > 2.txt has been all the content of 0.txt (except Square Brackets) instead of only {G,H,I}. That is, the 2.txt content is as below:

{A,B,C},{D,E,F}
{G,H,I}

Edit Update 01:

The solution must have the same effect for a third input file as below, considering the third occurrence, that is, [{J, K, L}]. So the expected exit should be {J, K, L}.

[{A,B,C},{D,E,F}]
[{G,H,I}]
[{J,K,L}]

For all purposes for the nth occurrence of [{x, y, z, ..}] (respected the condition of no text out of [ and ], and no blank line) Any solution given should extract to the Output file exactly {x, y, z, ..}.

4 Answers

how to extract the text between [ and ] with the given record number

You may try this gnu-awk command that will work irrespective of presence of line break between bracket pairs

awk -v n=2 -v RS='\\[[^]]*]' 'RT && NR == n {print substr(RT, 2, length(RT)-2)}' file

{G,H,I}

Since we are using custom RS of [...] it will print correct record no matter if 2nd pair of [...] is in first line or second line.

With GNU awk for FPAT:

$ awk -v FPAT='[^][\n]+' -v RS='^$' -v n=2 '{print $n}' 0.txt
{G,H,I}

$ awk -v FPAT='[^][\n]+' -v RS='^$' -v n=2 '{print $n}' 1.txt
{G,H,I}

With any awk and assuming you don't have any blank lines in the input:

$ awk -v RS= -F '][[:space:]]*[[]|^[[]|]$' -v n=2 '{print $(n+1)}' 0.txt
{G,H,I}

$ awk -v RS= -F '][[:space:]]*[[]|^[[]|]$' -v n=2 '{print $(n+1)}' 1.txt
{G,H,I}

Here's an alternate approach assuming your input doesn't have any non-newline characters outside of [] delimiters. This will work with any awk.

$ tr '[]' '\n' <ip.txt | awk -v RS= -v ORS= 'NR==2'
{G,H,I}

The tr command will replace all [] characters with newline characters. The awk command uses 2 or more consecutive newlines as record separator. Any excess newlines at the beginning of the input will be ignored. So, you can now just use the record number to get the desired output.

If you preprocess the data with grep, the extraction becomes trivial, e.g.:

n=3
<0.txt grep -oE '\{[^}]+\}' | sed -n ${n}p
<1.txt grep -oE '\{[^}]+\}' | sed -n ${n}p

Output :

{G,H,I}
{G,H,I}

Edit - Change in OPs requirements

If what you want is the contents of the square-brackets, then a minor change to this solution would still work, e.g.:

n=3
<new.txt grep -oE '\[[^]]+\]' | tr -d '[]' | sed -n ${n}p

Output:

{J,K,L}
Related