Delete multiple lines in a file

awksedtext processing

Usually I find my answers in the previously answered questions, but not this time (or I don't understand the answers and can't modify them to do what I want them to do), so I'm asking my first question here.

My input files look like

# -*- coding: utf-8 -*-

[attachment]

[browser]


[changeset]

[components]
tracopt.versioncontrol.svn.svn_fs.subversionconnector = enabled
tracopt.versioncontrol.svn.svn_prop.subversionmergepropertydiffrenderer = enabled 
tracopt.versioncontrol.svn.svn_prop.subversionmergepropertyrenderer = enabled
tracopt.versioncontrol.svn.svn_prop.subversionpropertyrenderer = enabled

[header_logo]

[inherit]
file = /etc/trac/trac.ini

[logging]

I'd like to remove all empty sections like attachment, browser, changeset, header_logo and logging. I'd only keep the sections that aren't empty. The output file should look like

# -*- coding: utf-8 -*-

[components]
tracopt.versioncontrol.svn.svn_fs.subversionconnector = enabled
tracopt.versioncontrol.svn.svn_prop.subversionmergepropertydiffrenderer = enabled
tracopt.versioncontrol.svn.svn_prop.subversionmergepropertyrenderer = enabled
tracopt.versioncontrol.svn.svn_prop.subversionpropertyrenderer = enabled

[inherit]
file = /etc/trac/trac.ini

This should happen in a bash script. I've thought of using sed : looking for a regex \[.+\]\n(\n)+(?=\[) but this doesn't seem to work with sed because I should know in advance how many lines the regex will be and use N accordingly. The regex should also work with EOF instead of the final \[, but I can probably do this if I find the way to do it for the \[.

Any idea how I could do this? Is there a better way than sed?

Best Answer

It is a bit messy with sed but possible:

sed -n '
:start
/^\[/{
    h
  :loop
    n
    /^\[/b start
    /^$/b loop
    x;p;g
}
p'

-n means print nothing by default. :start is just a label for a later goto. We match lines beginning [ and start a group ({...}) of commands. We copy the line to the hold space (h). We get the next line (n). If it begins [ we had an empty section, so goto (b) the start again.

If the line is empty (/^$/) we read another line (goto loop). The line is not empty so we exchange the line with the held section header (x), print the section header (p), get the current line back (g) and continue out of the group of commands to print (p) the line. This last (p) also prints non-section headers.

Related Question