SyncMaster
SyncMaster

Reputation: 9966

How to add lines after a pattern using sed

In shell script, how can I add lines after a certain pattern? Say I have the following file and I want to add two lines after block 1 and blk 2.

abc
def

[block 1]
    apples = 3
    grapes = 4

[blk 2]
    banana = 2
    apples = 3

[block 1] and [blk 2] will be present in the file.

The output I am expecting is below.

abc
def

[block 1]
    oranges = 5
    pears = 2
    apples = 3
    grapes = 4

[blk 2]
    oranges = 5
    pears = 2
    banana = 2
    apples = 3

I thought of doing this with sed. I tried the below command but it does not work on my Mac. I checked these posts but I couldn't find what I am doing wrong.

$sed -i '/\[block 1\]/a\n\toranges = 3\n\tpears = 2' sample2.txt
sed: 1: "sample2.txt": unterminated substitute pattern

How can I fix this? Thanks for your help!

[Edit] I tried the below and these didn't work on my Mac.

$sed -E '/\[block 1\]|\[blk 2\]/r\\n\\toranges = 3\\n\\tpears = 2' sample2.txt
abc
def

    [block 1]
        apples = 3
        grapes = 4

    [blk 2]
        banana = 2
        apples = 3

$sed -E '/\[block 1\]|\[blk 2\]/r\n\toranges = 3\n\tpears = 2' sample2.txt
abc
def

    [block 1]
        apples = 3
        grapes = 4

    [blk 2]
        banana = 2
        apples = 3

Awk attempt:

$awk -v RS= '/\[block 1\]/{$0 = $0 ORS "\toranges = 3" ORS "\tpears = 2" ORS}
      /\[blk 2\]/{$0 = $0 ORS "\toranges = 5" ORS "\tpears = 2" ORS} 1' sample2.txt
abc
def

    [block 1]
        apples = 3
        grapes = 4

    [blk 2]
        banana = 2
        apples = 3
    oranges = 3
    pears = 2

    oranges = 5
    pears = 2

Upvotes: 1

Views: 2836

Answers (3)

potong
potong

Reputation: 58578

This might work for you (GNU sed):

sed '/^\[\(block 1\|blk 2\)\]\s*$/{n;h;s/\S.*/oranges = 5/p;s//pears = 2/p;x}' file

Locate the required match, print it and then store the next line in the hold space. Replace the first non-space character to the end of the line with the first required line, repeat for the second required string and then revert to the original line.

Upvotes: 1

randomir
randomir

Reputation: 18697

Note that the text provided to the a command has to be on a separate line:

sed '/\[block 1\]/ {a\
\toranges = 3\n\tpears = 2
}' file

and all embedded newlines have to be escaped. Another way to write it (probably more readable):

sed '/\[block 1\]/ {a\
    oranges = 3\
    pears = 2
}' file

Also, consider the r command as an alternative to the a command when larger amounts of text have to be inserted (e.g. more than one line). It will read data from a text file provided:

sed '/\[block 1\]/r /path/to/text' file

To handle multiple sections with one sed program, you can use the alternation operator (available in ERE, notice the -E flag):

sed -E '/\[block 1\]|\[blk 2\]/r /path/to/text' file

Upvotes: 4

anubhava
anubhava

Reputation: 786271

This awk should work with empty RS. This breaks each block into a single record.

awk -v RS= '/\[block 1\]/{$0 = $0 ORS "\toranges = 3" ORS "\tpears = 2" ORS} 
      /\[blk 2\]/{$0 = $0 ORS "\toranges = 5" ORS "\tpears = 2" ORS} 1' file

abc
def
[block 1]
    apples = 3
    grapes = 4
    oranges = 3
    pears = 2

[blk 2]
    banana = 2
    apples = 3
    oranges = 5
    pears = 2

Upvotes: 1

Related Questions