1

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?

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
stackmate
  • 908
  • 9
  • 17
  • Related: [sed - Insert multiline string containing special characters to a template file using bash - Stack Overflow](http://stackoverflow.com/questions/6572309/insert-multiline-string-containing-special-characters-to-a-template-file-using-ba) – Lri Jul 07 '11 at 06:04

1 Answers1

0

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thanks Jonathan - I appreciate your response, though, indeed your solution inserts the text of insert.txt once per line found between the delimiters. I definitely prefer the option of using the "r" command instead of the "c" but doesn't seem like this will work. – stackmate Oct 26 '10 at 18:37
  • @stackmate: try the fixed version - sorry about being distracted. I plan to delete this comment if you agree the solution works. – Jonathan Leffler Oct 26 '10 at 18:48
  • Thanks Jonathan - I did want to preserve the delimiters though (in your case, start and end). – stackmate Oct 26 '10 at 18:59
  • @stackmate: It's probably easiest to print new delimiter before and after reading in the insert file - make that into a multi-action operation. – Jonathan Leffler Oct 26 '10 at 20:32