9

I am trying to replace a word with a text which spans multiple lines. I know that I can simply use the newline character \n to solve this problem, but I want to keep the string "clean" of any unwanted formatting.

The below example obviously does not work:

read -r -d '' TEST <<EOI
a
b
c
EOI

sed -e "s/TOREPLACE/${TEST}/" file.txt

Any ideas of how to achieve this WITHOUT modifying the part which starts with read and ends with EOI?

Chris Seymour
  • 83,387
  • 30
  • 160
  • 202
Andreas
  • 93
  • 1
  • 1
  • 3

4 Answers4

10

Given that you're using Bash, you can use it to substitute \n for the newlines:

sed -e "s/TOREPLACE/${TEST//$'\n'/\\n}/" file.txt

To be properly robust, you'll want to escape /, & and \, too:

TEST="${TEST//\\/\\\\}"
TEST="${TEST//\//\\/}"
TEST="${TEST//&/\\&}"
TEST="${TEST//$'\n'/\\n}"
sed -e "s/TOREPLACE/$TEST/" file.txt

If your match is for a whole line and you're using GNU sed, then it might be easier to use its r command instead:

sed -e $'/TOREPLACE/{;z;r/dev/stdin\n}' file.txt <<<"$TEST"
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
2

You can just write the script as follows:

sed -e 's/TOREPLACE/a\
b\
c\
/g' file.txt

A little cryptic, but it works. Note also that the file won't be modified in place unless you use the -i option.

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
  • Thanks. I know about the -i option. Actually, I want to use a variable for better readability and I do not want to touch the contents of the variable. Actually ... it's rather that I would like to know how I can do this for future reference. Do you know a solution to this problem that does not involve the modification of the first 5 lines? – Andreas Jul 13 '11 at 20:23
  • The question is that the `read` converts the carriage returns into spaces, so you should be inserting the carriage returns again anyway. – Diego Sevilla Jul 13 '11 at 20:29
1

tricky... but my solution would be :-

read -r -d '' TEST <<EOI
a
b
c
EOI

sed -e "s/TOREPLACE/`echo "$TEST"|awk '{printf("%s\\\\n", $0);}'|sed -e 's/\\\n$//'`/g" file.txt

Important: Make sure you use the correct backticks, single quotes, double quotes and spaces else it will not work.

terryy
  • 11
  • 3
-1

An interesting question..

This may get you closer to a solution for your use case.

read -r -d '' TEST <<EOI
a\\
b\\
c
EOI

echo TOREPLACE | sed -e "s/TOREPLACE/${TEST}/"
a
b
c

I hope this helps.

Mat
  • 202,337
  • 40
  • 393
  • 406
shellter
  • 36,525
  • 7
  • 83
  • 90
  • For the moment I will go with this ... interestingly, that doesn't seem to be as trivial as I thought it was ... thanks – Andreas Jul 20 '11 at 15:03