0

I want to edit a file using sed/awk. The file is made up of several configuration sections, like this:

SECTION 1 BEGIN
some stuff
SECTION END

SECTION 2 BEGIN
some stuff
some more stuff
important line
SECTION END

I want to add important line to the end of SECTION 2 if it doesn't already exist, preferably as a command one liner. I've been looking at the fgrep/sed combo in this question, but I don't quite understand how to adapt it for what I need.

Note: there may be blank lines in the sections.

Many thanks.

Community
  • 1
  • 1
simon
  • 1,840
  • 2
  • 18
  • 34

2 Answers2

5

Using awk:

awk '
  $0 == "SECTION 2 BEGIN" { inSec2 = 1 } 
  inSec2 && $0 == "important line" { hasImportant = 1 } 
  inSec2 && $0 == "SECTION END" { 
    if (!hasImportant) { print "important line" } 
    inSec2 = 0
  }
  1'
Michael J. Barber
  • 24,518
  • 9
  • 68
  • 88
  • Thanks Michael, that works perfectly. I really need to learn awk, it looks bad ass! – simon Apr 19 '13 at 10:35
  • Good solution. Just small comments. I think instead of `$0 == "..."` the shorter `/^...$/` could be used. And instead of setting `hasImportant` in the second condition the `inSec2` variable could be cleared. So in the third condition the `if` statement become useless. Just `print` the "important line". – TrueY Apr 19 '13 at 11:02
  • Also "important line" string could be defined once as `awk -vimplin="important line"` (defining in `BEGIN` block is longer). Then `implin` could be used later. – TrueY Apr 19 '13 at 11:09
  • 1
    @TrueY You suggest enough changes that I'd recommend you just post another solution to show an alternate approach. – Michael J. Barber Apr 19 '13 at 11:23
  • Just realised that this needs to go in tcsh, so the multi line command won't work. Can you reformat the command so it is literally on one line? – simon Apr 19 '13 at 11:59
  • @simon surely you can do that yourself!? If you are using `tcsh` and really don't have `bash` you also need to change `(!hasImportant)` to `(hasImportant==0)`. – Chris Seymour Apr 19 '13 at 13:51
  • @sudo_O: ??? The if is inside the awk script. It is nothing to do with bash. Isn't it? – TrueY Apr 19 '13 at 14:01
  • @TrueY Not true, using `!` with `csh` can be a pain http://www.grymoire.com/Unix/Csh.html#uh-1 – Chris Seymour Apr 19 '13 at 14:13
  • 1
    @simon Sorry, I don't know really know the details of scripting in tcsh. If you can't figure it out, just save what I've given in my answer in a file, stick `#! /bin/sh` at the top, make it executable with `chmod` (or whatever the tcsh equivalent is), and pipe your text through it. – Michael J. Barber Apr 19 '13 at 14:17
  • @sudo_O: Ok, you may be right. Based on the doc, `\!` could work. But anyway the whole `hasImportant` stuff could be skipped. – TrueY Apr 19 '13 at 14:18
  • @TrueY yes you could also do that but then you break the script with `bash` so it is safer to be explicit here `(hasImportant==0)`. – Chris Seymour Apr 19 '13 at 14:21
  • Unfortunately my situation is this: We need to edit a config file on some very locked down hardware appliances that run some variant of redhat/centos. We want to be able to configure these devices by pasting a configuration into an SSH session. The default shell is tsch, we can run sh but I would rather not. – simon Apr 19 '13 at 15:11
3

Based on Michael's solution there is a one-liner:

awk -vline="important line" '/^SECTION 2 BEGIN$/{f=1}f&&$0==line{f=0}f&&/^SECTION END$/{print line;f=0}1'<<EOT
SECTION 1 BEGIN
some stuff
SECTION END

SECTION 2 BEGIN
some stuff
some more stuff
SECTION END

SECTION 2 BEGIN
some stuff
some more stuff
important line
SECTION END

SECTION 3 BEGIN
oops
SECTION END
EOT

Output:

SECTION 1 BEGIN
some stuff
SECTION END

SECTION 2 BEGIN
some stuff
some more stuff
important line
SECTION END

SECTION 2 BEGIN
some stuff
some more stuff
important line
SECTION END

SECTION 3 BEGIN
oops
SECTION END
TrueY
  • 7,360
  • 1
  • 41
  • 46
  • @simon: It is just the "here is the document". Same as if You write the lines between the `awk` and the last `EOT` line to a file and You do a ` – TrueY Apr 19 '13 at 16:04