35

Say I have a text file like this:

# custom content section
a
b

### BEGIN GENERATED CONTENT
c
d
### END GENERATED CONTENT

I'd like to replace the portion between the GENERATED CONTENT tags with the contents of another file.

What's the simplest way to do this?

4 Answers 4

45
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file
7
  • 1
    Excellent. sed can do so much more than just s/.../...!
    – DevSolar
    Jun 22, 2012 at 8:28
  • 3
    The r insert_file command must be the last thing on its line. Note that neither whitespace nor comments are allowed after it. The code was tested using GNU sed with the --posix option enabled, and it worked as expected, so it should work with any posix compliant sed.
    – Peter.O
    Jul 12, 2014 at 1:58
  • 1
    Holy moly, that's cool! This is going in my sed dictionary! Superbly useful and beautifully simple. Thank you! Jan 14, 2015 at 17:39
  • 2
    Note an in-place editing requires you capture the output of sed (e.g. output=$(sed -e "..." existing_file)) and then perform the replacement in a second pass (e.g. echo "$output" > existing_file) since trying to redirect into a file you're reading from will cause it to truncate before contents are read. Aug 2, 2016 at 12:44
  • 3
    can someone explain the command. Feb 19, 2019 at 10:52
7
newContent=`cat new_file`
perl -0777 -i -pe "s/(### BEGIN GENERATED CONTENT\\n).*(\\n### END GENERATED CONTENT)/\$1$newContent\$2/s" existing_file
0
5

Using a heredoc and the ed line editor:

ed -s FILE1 <<EOF
/### BEGIN GENERATED/+,/### END GENERATED/-d
/### BEGIN GENERATED/ r FILE2
w
q
EOF

The first line inside the heredoc is to delete (d) the line after (+) the ### BEGIN GENERATED and the line before (-) the ### END GENERATED...

The second line is to insert FILE2 after the line ### BEGIN GENERATED.

4
  • Using a heredoc and the ed line editor. The first line inside the heredoc is to deleted 'd' the line after '+' the '### BEGIN gENERATED...' and the line before '-' the '### END GENERATED...' the second line is to insert FILE2 after the line ### END GENERATED...'
    – Jetchisel
    Sep 3, 2014 at 23:27
  • sorry what i meant was insert FILE2 after the line '### BEGIN GENERATED..'
    – Jetchisel
    Sep 3, 2014 at 23:47
  • Take it easy on me folks, it is after all my first time :-). Also i might have used the word the same but the other solution does not use a heredocs but a printf and a pipe. Any way apologies if i have made a mistake :-)
    – Jetchisel
    Sep 8, 2014 at 0:41
  • 1
    Thanks, very readable! Btw - instead of r FILE2 you can say r !command to read from a different script.
    – Kos
    Sep 18, 2019 at 10:25
4

Warning: This is definitely not the simplest way to do it. (EDIT: bash works; POSIX grep is fine too)

If the main text is in file "main" and the generated content is in file "gen", you could do the following:

#!/bin/bash
BEGIN_GEN=$(cat main | grep -n '### BEGIN GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
END_GEN=$(cat main | grep -n '### END GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
cat <(head -n $(expr $BEGIN_GEN - 1) main) gen <(tail -n +$(expr $END_GEN + 1) main) >temp
mv temp main
2
  • Does this work? I think your last line will open main for writing, clearing it, before it is read by cat.
    – chepner
    Jun 22, 2012 at 14:05
  • @chepner Crap, you're right. The rest works, though. I'll fix it.
    – Dr Kitty
    Jun 22, 2012 at 18:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .