Issue
I have a file named "insert.txt". It can look like this (or uglier):
ASDFG?|??|?\/\HJKL<MNBVCXZQWERTYUIOP
zxvbnmlkjhgfdsaqwertyuiop
123"'`~4567890987654321!@#$%^&*()
@#$%^&*()+_}{":?>
And I want to replace a block of text in a target file (target.txt) which is delimited by "STARTSTACKOVERFLOW" to "STOPSTACKOVERFLOW". (I am simplifying the question a little here, but it's the same).
The bash script I use to do this is:
TARGETFILE=target.txt
SOURCEFILE=insert.txt
SOURCETXT="$(<$SOURCEFILE)"
DELIMTXT=$(printf "%q" "$SOURCETXT")
sed -i -e "/STARTSTACKOVERFLOW/,/STOPSTACKOVERFLOW/cSTARTSTACKOVERFLOW\n\n${DELIMTXT}\n\nSTOPSTACKOVERFLOW\n" $TARGETFILE
The problem is that what is pasted into "target.txt" is actually ANSI-C quoted:
$'ASDFG?|??|?\/\HJKL<MNBVCXZQWERTYUIOP
zxvbnmlkjhgfdsaqwertyuiop
123"'`~4567890987654321!@#$%^&*()
@#$%^&*()+_}{":?>'
Note the $'' added.
The reason is that the printf "%q" is producing this quoting style. I would like to avoid that - though need it because I must escape all the badness in this file.
Is there a better way of doing the above using bash and sed?
Solution
POSIX sed has an 'r' command to read from a file. So:
sed -i -e '/STARTSTACKOVERFLOW/,/STOPSTACKOVERFLOW/r large.txt' target.txt
The only issue is whether the file is read once, or once per line between the start and stop lines. I suspect it is read once per line...and working out how to throw the extra lines away is harder...but maybe:
sed -i -e '/STOPSTACKOVERFLOW/r large.txt' \
-e '/STARTSTACKOVERFLOW/,/STOPSTACKOVERFLOW/d' target.txt
Simple demo
This version removes the start and end markers.
$ cat data
sdasas
adsasdas
start
more
more
end
sdasda
sdasdad
$ cat replace
replace1
replace2
replace3
$ sed -e '/^end$/r replace' -e '/start/,/end/d' data
sdasas
adsasdas
replace1
replace2
replace3
sdasda
sdasdad
Preserving the start and end markers
$ cat sedfile
/^end$/{
a\
start
r replace
a\
end
}
/^start$/,/^end$/d
$ sed -f sedfile data
sdasas
adsasdas
start
replace1
replace2
replace3
end
sdasda
sdasdad
$
This is fiddlier - I would not try to do it without using a file for the script, but you could do so if you wanted to. It is not a one-liner, though.
Answered By - Jonathan Leffler Answer Checked By - David Goodson (WPSolving Volunteer)