6

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?

  • 4
    What you have there looks like an INI/CFG file (i.e. [sections] and a = b key-value pairs. I would always use a tool that understands the that format and use that to modify the file. That way e.g. line wrapping is more likely to be handled correctly. (Python has its configobject library, I assume that perl and ruby have similar standard libraries). – Anthon Oct 12 '15 at 13:13
8

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.

  • Thanks, it does what I wanted and I understand it. I marked the answer useful and accepted your solution, if there's anything else I should do to thank you or close the topic, please let me know. – trapangle Oct 12 '15 at 13:39
2

I come with the following awk

BEGIN { empty=0 ; section = "" ; }
substr($0,1,1) == "[" { section = $0 ; next ; }
NF == 0 { if ( empty++ ) print ; section = "" ; next ; }
NF > 0  { if ( section != "" ) print section ; print ; section = "" ; }

to be called with

awk -f pgm.awk infile > outfile

however, as Terdon mention, It might be best to use library, this file format in not that confidential, besides library will take care of cr, cr/nl and nl end of line.

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.