0

I need to concatenate a variable number of lines between braces, the braces are nested so only braces that begin with a specific prefix pattern to the brace need to be concatenated:

header {

category1 (a) {
field1 : value1 ;
field2 : value2 ;
...
fieldn : valuen ;
}

new cat1 (b) {
newfield1 : newvalue1 ;
newfield2 : newvalue2 ;
....
newfieldn : newvaluen ;
}

...

}

The category and field names are variable, the trailing ";" may or may not have a preceding space. Any line may have spaces or tabs in front of it or between words/delimiters/etc.

The output should look like:

header {
category1 (a) { field1 : value1 ; field2 : value2 ; ... fieldn : valuen ; }
new cat1 (b) { newfield1 : newvalue1 ; newfield2 : newvalue2 ; .... newfieldn : newvaluen ; }
}

I'm using CentOS, so sed/awk/perl are available.

Thanks!

1
  • 1
    What is the specific prefix you are referring to in "braces that begin with a specific prefix"? Is it "cat"? Or is it irrelevant? Can braces be further nested (e.g. "header { cat { name : foo { bar } } }")? – fra-san Apr 27 '20 at 21:16
2

Try

$ awk '
/^ *$/          {next
                }
/cat.*{/        {while (! /}/)  {getline X
                                 $0 = $0 X
                                }
                }
1
' file
header {
category1 (a) {field1 : value1 ;field2 : value2 ;...fieldn : valuen ;}
new cat1 (b) {newfield1 : newvalue1 ;newfield2 : newvalue2 ;....newfieldn : newvaluen ;}
...
}
1

With GNU awk for multi-char RS and RT this will do the bit in the middle:

$ awk -v RS='[^\n]+{[^{}]+}' '{$0=RT; $1=$1} RT' file
category1 (a) { field1 : value1 ; field2 : value2 ; ... fieldn : valuen ; }
new cat1 (b) { newfield1 : newvalue1 ; newfield2 : newvalue2 ; .... newfieldn : newvaluen ; }

Printing the first and last lines is as simple as head -1 and tail -1:

$ head -1 file; gawk -v RS='[^\n]+{[^{}]+}' '{$0=RT; $1=$1} RT' file; tail -1 file
header {
category1 (a) { field1 : value1 ; field2 : value2 ; ... fieldn : valuen ; }
new cat1 (b) { newfield1 : newvalue1 ; newfield2 : newvalue2 ; .... newfieldn : newvaluen ; }
}

or figure out how to do it in that awk script too if you care, it's not particularly hard jut requires a bit more thought than I'm up for right now!

0

This will do mostly what you want, though it won't add spaces between values and semicolons if they're left out...

Assuming your input is in file.txt:

tr "\n" " " < file.txt | tr "\t" " " | tr -s " " | sed "s/}/}\n/g" | sed "s/header {/header {\n/" | sed "s/^ //g"

1) Replace all the existing newlines with spaces

tr "\n" " "

2) Replace all tabs with spaces

tr "\t" " "

3) Replace all runs of spaces with a single space

tr -s " "

4) Replace all close-brackets with close-bracket followed by newline

sed "s/}/}\n/g"

5) Add a newline after the initial "header {"

sed "s/header {/header {\n/"

6) Remove the leading space on subsequent lines

sed "s/^ //g"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.