1

I have the output from a command (plantuml -language; see List of keywords, predefined names, symbols for codeless language module for BBEdit? for the background) which effectively looks like this:

;type1
;3
@fff
@ggg
hhh

;preprocessor
;1
!undef

;keyword
;3
!undef
test
somemore

.
.
.

The first ; denotes the name, the second directly following ; in the next line the number of items. The items are followed by an empty line, and the next block begins.

I would like to split the whole output into separate files (named after the name), which I would like to process further.

File type1:

@fff
@ggg
hhh

File preprocessor:

!undef

File keyword:

!undef
test
somemore

How can I do this with tools like awk or sed? Or is there an easier tool?

2
  • Welcome to the site. To make it easier for contributors to help you, please edit your question to include an example of the desired output.
    – AdminBee
    Jan 20, 2020 at 13:01
  • Thanks - I have done so.
    – Rainer
    Jan 20, 2020 at 13:04

2 Answers 2

1

Maybe not the most elegant solution, but this seems to do it:

awk -F';' '
  NF==0 { next }
  NF>1 && $1=="" { filename=$2; getline; next }
  { print > filename }
' file
  • If the number of fields is zero (blank line), continue with the next line.
  • If the number of fields is greater one (a line starting with a semicolon), set variable filename, get the next line, but don't process it (skip it) and continue with the next line.
  • Otherwise, print the line and redirect the output to the file filename.
3
  • Thanks. That works.
    – Rainer
    Jan 20, 2020 at 13:35
  • You will have a problem if any of the "data" lines contains a semicolon. Jan 20, 2020 at 17:35
  • @glennjackman Good catch! I changed NF>1 to NF>1 && $1=="" to make it more robust.
    – Freddy
    Jan 20, 2020 at 18:33
0

I would do

awk -F '\n' -v RS= '{f=substr($1, 2); for (i=3; i<=NF; i++) print $i > f}' file

Note that in awk-speak, a file is composed of "records", and a record contains "fields". By default, a record == one line, but this can be configured.

This uses the input record separator RS variable as the empty string, which means that sequences of empty lines separate records. I set the field separator to newline. Together, each "paragraph" of the file is a record, and each line in a paragraph is a field.

The substr call just omits the leading semicolon.

I'm not actually checking that the number of lines of data is actually equal to the "n" value of the 2nd ; line.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .