Search code examples
sedinsertappendmatchcodeblocks

SED INSERT block of code BEFORE matched block


I have a text file I want to edit during a script excecution. I want to pass from the text on left to the text on right using sed insert:

INSERT BEFORE: from:

[...]
[ placeholder ]
Categ         #n
ItemName      1
[...]
[ placeholder ]
Categ         #n
ItemName      2
[...]

to:

[...]
[ placeholder ]
Categ         #n
ItemName      1
[...]
**new_line1**        <<<--- INSERT BEFORE
**new_line2**        |||
**new_line3**        |||
[ placeholder ]      <<<--- 3-lines match
Categ         #n     |||
ItemName      2      |||
[...]

I have tried to adapt sed append lines to sed insert. The appending works, the insert does not. The match to append was 2 lines one after the other. In the insert, the match it is 3 lines and I tried to match the first and the last, as I don't know how to match the entire 3-lines block.

APPEND AFTER:

sed -e '/^\[ placeholder \]\/ItemName      2/a \\nnew_line1\nnew_line2\nnew_line3' input.txt

and it works from:

[...]
[ placeholder ]
ItemName      1
[...]
[ placeholder ]
ItemName      2
[...]

to:

[...]
[ placeholder ]
ItemName      1
[...]
[ placeholder ]     <<<--- 2-lines match
ItemName      2     |||
**new_line1**       <<<--- APPENDED AFTER
**new_line2**       |||
**new_line3**       |||
[...]

I have tried to use the syntax examples in this post, but with no success. The sed - Stream Editor


Solution

  • If your input does not contain NUL bytes you could try the following with GNU sed:

    $ from='\[ placeholder \]\nCateg         #n\nItemName      2\n'
    $ to='**new_line1**\n**new_line2**\n**new_line3**\n'
    $ sed -Ez "s/(^|\n)($from)/\1$to\2/" input.txt
    [...]
    [ placeholder ]
    Categ         #n
    ItemName      1
    [...]
    **new_line1**
    **new_line2**
    **new_line3**
    [ placeholder ]
    Categ         #n
    ItemName      2
    [...]
    

    With the -z option the input is treated as a set of lines, each terminated by a zero byte (the ASCII NUL character) instead of a newline. If the input does not contain NUL bytes this allows to process the entire file at once. Of course you must properly escape special characters in from and to.