1

I have a file sample.txt like this:

lots of text
lots of text


#nvram = [
#   these
#   could
#   be,
#   anything
#]

lots of text
lots of text

and I want to add some text "foobar" to get this:

lots of text
lots of text


#nvram = [
#   these
#   could
#   be,
#   anything
#]
foobar

lots of text
lots of text

I have looked at some related threads and tried a bunch of stuff but have not been able to join the information together in the correct way.

multiline matching: How can I use sed or ex to replace a block (multi-line code) with new block of text (code)? https://stackoverflow.com/questions/11234001/replace-multiple-lines-using-sed How can I use sed to replace a multi-line string?

appending: How to add a new line after the "test message1" using sed?

I've been trying stuff like this:

sed  '/^#nvram = \[$/{
    N
    ^.*$
}/abc123/' sample.txt

sed '/^#nvram = \[$/ {N; s/\<^#nvram = \[$\>\n<^.*$\>/abc123/g}' sample.txt

sed '/^#nvram = \[$/ {N; s/\<#nvram = \[\>\n\<.*\>/abc123/g}' sample.txt

sed '/^#nvram = \[$/ {N; s/#nvram = \[\n.*/abc123/g}' sample.txt

sed '/^#nvram = \[$/ {N; /#nvram = \[\n.*/abc123/a}' sample.txt

sed '/^#nvram = \[$/ {N; /#nvram = \[(\n.*){1,}/abc123/a}' sample.txt


sed '/^#nvram = \[$/!b;n;cABC' sample.txt

sed '/^#nvram = \[$/N;cABC' sample.txt

sed '/^#nvram = \[$/N/#\]/a;cABC' sample.txt


sed '/^#nvram = \[$/,/#\]/{/^#nvram = \[$/n;/#\]/!{s/./abc/g}}' sample.txt

sed '/^#nvram = \[$/,/#\]/{/^#nvram = \[$/n;/#\]/!{/abc/a}}' sample.txt

sed '/^#nvram = \[$/,/#\]/{/^#nvram = \[$/n;/#\]/!/a abc}' sample.txt

sed '/^#nvram = \[$/,/#\]/{/^#nvram = \[$/n;/#\]/;/a abc}' sample.txt

sed '/^#nvram = \[$/,/#\]/{/^#nvram = \[$/n;/#\]/a abc}' sample.txt


But so far I have not succeeded.

2

How about using a loop?

sed '/^#nvram = \[/{
:a                          
N                                                  
/\n#\]/!ba                                                                  
a\
foobar
}
' sample.txt

Explanation:

:a              # begin loop
N               # append next line to pattern space
/\n#\]/!ba      # if we haven't matched the end marker yet, branch back to a
a\              # append after loop exits
foobar

At least in GNU sed, this can be written as a one-liner

sed -e '/^#nvram = \[/{:a; N; /\n#\]/!ba; a\foobar' -e '}' sample.txt
  • Thank you! Sorry about the slow response, I had some distractions. All of the answers worked for me but I'm crediting you because you were first. – Stonecraft Aug 6 at 19:33
1

With GNU sed for -z:

$ sed -z 's/#nvram = \[.*\]/&\nfoobar\n/' file
lots of text
lots of text


#nvram = [
#   these
#   could
#   be,
#   anything
#]
foobar

lots of text
lots of text

You may need to tweak the regexp depending what you really mean by "anything" (e.g. can it contain a ]) and whether or not you have other similar blocks in your file.

This would be more robust, for example, if anything doesn't include ]s and you have other similar blocks in your input:

sed -z 's/#nvram = \[[^]]*\]/&\nfoobar\n/' file
  • 1
    That works too, thanks! – Stonecraft Aug 6 at 19:33
1

I'll pick one of the approaches you took and show you how to make it work, so that it resonates and also stays with you:

$ sed -e '
   /^#nvram = \[$/,/^#]$/!b
   /^#]$/a\
Foobar
' sample.txt

I personally don't like the above nd do somewhat differently:

$ sed -e '
   /^#nvram = \[$/,/^#]$/!b
   /^#]$/G
   s/\n/&Foobar/
' sample.txt
  • Nice, thanks! That also works. – Stonecraft Aug 6 at 19:34
1

Here's also a simple sed:

sed '/#nvram = \[/,/#]/ s/#]/#]\nfoobar/' file

It finds a line in which the #nvram = [ has occurred and then all the lines after that and until the first occurence of an #] is addressed, then you substitute the #]\nfoobar for #].

  • In one line, cool! Thanks! – Stonecraft Aug 6 at 19:34

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.