replace block of text with content of another file

Hello,

file1:

not to be changed
not to be changed
<start>
old stuff
old stuff
old stuff
<end>
not to be changed
not to be changed

file2:

new text
new text

desired output:

not to be changed
not to be changed
<start>
new text
new text
<end>
not to be changed
not to be changed

What I have so far:

sed '/<start>/,/<end>/ {/<start>/b;/<end>/b;d}' file1 | sed '/<start>/r file2'

Works all right but I was expecting to come up with something more straight forward, more terse. Also, this sed solution uses two processes. I couldn't get it work in one.

I tried also awk with getline and a redirection from the file2 but to it was also too complicated. I have that strange feeling that there must be some simple solution but couldn't find it.

What I have so far with awk:

 awk '!flag{print}flag{getline < "file2";print}/start/{flag=1}/end/{flag=0;print}' file1

output:

not to be changed
not to be changed
<start>
new text
new text
old stuff
<end>
<end>
not to be changed
not to be changed
awk '/start/{f=1;print;while (getline < "file2"){print}}/end/{f=0}!f' file1
1 Like

Nice! Thank you.

---------- Post updated at 04:02 PM ---------- Previous update was at 02:51 PM ----------

The following also works :

awk 'NR==FNR{a[NR]=$0;next}/start/{f=1;print;for (i in a) print a}/end/{f=0}!f' file2 file1 

I benchmarked the two methods and the "getline / redirection" thing seems to be much faster on large files. Something like 5 times faster on a large file2 file (18.000 lines)

If all of your replacement lines are identical (as they are in your original post), then yes, it works. However, if the lines in File2 are not identical, and if you wish for their order to be preserved, then you cannot use that approach; you would need to store file2 in a string or use a loop with a counter (c-style for or while), to do it correctly.

$ jot 5
1
2
3
4
5
$ jot 5 | awk '{a[NR]=$0} END {for (i in a) print a}'
2
3
4
5
1

Regards,
Alister