Use sed to insert a string after matching a block of text

I am trying to use sed to insert a line after [Block B] in the following file:

[Block A] line 1 line 2 [Block B] line 1 line 2 [Block C] line 1 line 2 

The command I used:

 sed '/\[Block B\]/,/^$/a\inserted line' file 

The correct / desired result should be:

 [Block B] line 1 line 2 inserted line 

However, I got this instead:

 [Block B] inserted line line 1 inserted line line 2 inserted line 

Please tell me how I can get the desired result using sed. Thanks!

+4
source share
3 answers
 sed -e '/\[Block B\]/{:a;n;/^$/!ba;i\inserted line' -e '}' 
+12
source

I found this question looking for a solution to my own problem that was similar, but a little different. I adapted the answers here to solve my problem.

I needed to insert some text at the end of the block inside the configuration file, for example:

 name1 { ... } name2 { ... inserted text line 1 inserted text line 2 } name3 { .... } 

To do this, I took @toyntz's comment above and adapted it this way:

 /^name2 {/,/^}/{ /^}/i\ inserted text line 1 /^}/i\ inserted text line 2 } 

This is just a sed expression; it can be placed in a file and executed using sed -f as follows:

 $ sed -f sed_expression data_file 

This first expression searches for a range of lines starting with name2 { , occurring at the beginning of a line and ending with } , also occurring at the beginning of a line. This selects the unit to work. The rest of the expression is enclosed in { curly brackets } and works in the selected range. It contains one command for each line that we want to insert, each with the expression /^}/ , which corresponds to a line with a closing curly bracket, and then insert i to insert a line of text. It is followed by i c \ , so leading spaces are also inserted into it.

Then I took the expression a little further, replacing the two insert commands with one:

 /^name2 {/,/^}/{ /^}/i\ inserted text line 1\ inserted text line 2 } 

Here, the text to be inserted with one command extends to the next two lines. Pay attention to the additional trailing \ in the first line to continue a single command.

Then I reduced it to one line. This makes it dirty and hard to read, but it still works:

 /^name2 {/,/^}/{/^}/i\ inserted text line 1\n inserted text line 2 } 

The two lines to be inserted are separated by the newline character \n . Astute readers will notice that there are actually two lines — you cannot put a closing shape at the end of the first line; therefore, the other answers above have a second expression. So above was the best I could do. To represent this on the bash command line:

 sed -e '/^name2 {/,/^}/{/^}/i\ inserted text line 1\n inserted text line 2' -e '}' data_file 

I wrote this long way in the hope that he will explain to someone who wants to insert at the end of a block of text how a sed expression can be written to achieve this. Sed expressions can be quite cryptic and hard to understand - hopefully my explanations will help in this regard.

+6
source

This may work for you (GNU sed):

 sed '/^\[Block B\]/,/^$/!b;/^$/i\inserted line' file 
0
source

All Articles