0

I am writing a script to reformat some files. The details aren't important other than that the content replacing what is there contains newlines. Sed interprets the newlines as terminating the sed command and returns an error. I first tried this in gitbash on Windows, and then on CentOS 7. The below output shows the sed command failing once the newline is in the input file.

$ echo foobar > foobar.txt

$ echo foo | sed "s/foo/$(cat foobar.txt)/"
foobar

$ echo barfoo >> foobar.txt

$ cat foobar.txt
foobar
barfoo

$ echo foo | sed "s/foo/$(cat foobar.txt)/"
sed: -e expression #1, char 12: unterminated `s' command

I would want the output to be

foobar
barfoo

Is there an easy way (hacks are fine - this isn't for production) to convert the newlines to \n or escape them some other way?

2 Answers2

1
escaped_file_contents=$(<foobar.txt sed 's:[\/&]:\\&:g;$!s/$/\\/')
sed "s/foo/$escaped_file_contents/g"

Beware however that trailing empty lines in foobar.txt if any are removed.

See this similar Q&A for details.

Or with perl:

REPL=$(cat foobar.txt) perl -pe 's/foo/$ENV{REPL}/g'

Or getting perl to read the contents of foobar.txt by itself:

perl -pe '
  BEGIN {$/ = undef; $repl = <>; $_ = "\n"; chomp $repl}
  s/foo/$repl/g' foobar.txt -
  • running your command as is gives me foobar\ barfoo\. But 's:[\/&]:\\&:g;$!s/$/\\n/' gives me foobar\n barfoo\n, which I can work with. Thanks! – Y     e     z Oct 28 '19 at 15:16
0

With Gnu sed you can do as shown :

$ echo foo | sed -e 's/foo/cat foobar.txt/e'

The thing to note is that sed operates on the complete pattern space when using the s///e command. Also the trailing newlines shall be trimmed.

Or, with Perl :

 $ perl -lpe 's/foo/qx(cat foobar.txt)/e' 
  • That's usage of the e flag for the s command would only work for line that are exactly foo (and would call a shell and cat for each of those lines and read the content through a pipe. So you'd want sed 's/^foo$/cat foobar.txt/e' but you'd rather use the standard r command in that case. – Stéphane Chazelas Oct 28 '19 at 14:53
  • The perl one will include the trailing newline of foobar.txt in the replacement (and will also run cat for each occurrence of foo being replaced) – Stéphane Chazelas Oct 28 '19 at 14:55