34

What would be the sed command for mac shell scripting that would replace all iterations of string "fox" with the entire string content of myFile.txt.

myFile.txt would be html content with line breaks and all kinds of characters. An example would be

    </div>
  </div>
  <br>
  <div id="container2">
    <div class="question" onclick="javascript:show('answer2')";>

Thanks!

EDIT 1

This is my actual code:

sed -i.bkp  '/Q/{
s/Q//g
r /Users/ericbrotto/Desktop/question.txt
}' $file

When I run it I get:

sed in place editing only works for regular files. 

And in my files the Q is replaced by a ton of chinese characters (!). Bizarre!

Eric Brotto
  • 53,471
  • 32
  • 129
  • 174
  • See http://stackoverflow.com/questions/6684487/sed-replace-with-variable-with-multiple-lines/6685563#6685563 . This would be one solution. Good luck. – shellter Jul 22 '11 at 13:36
  • About the Edit 1... Your original files are available with the extension `.bkp`. What is the content of your `question.txt` file? Also, what is the content of the files referenced by `$file`. Is there some binary file? What is the encoding of them? – brandizzi Jul 22 '11 at 14:12
  • The content of the question.txt file is exactly the html shown above. The files referenced by $file are .txt files. Is there something wrong with my .bkp part? Should I change it to .txt? I will check the encoding of my question.txt file now. – Eric Brotto Jul 22 '11 at 14:21
  • There is no problem with your `-i.bkp` flag. The sed message makes me suspect that it, being the input files really text files, it is an encoding issue. It is _possible_ that you are iterating over some files and some binary file did just is in the list accidentally. Anyway, I'll expect more input about the problem :) – brandizzi Jul 22 '11 at 14:25
  • See also https://stackoverflow.com/questions/74917108/replace-string-with-file-content which demonstrates embedding the contents of another file in the middle of a line which contains other non-replaced text, too. – tripleee Dec 26 '22 at 10:00

3 Answers3

76

You can use the r command. When you find a 'fox' in the input...

/fox/{

...replace it for nothing...

    s/fox//g

...and read the input file:

    r f.html
}

If you have a file such as:

$ cat file.txt
the
quick
brown
fox
jumps
over
the lazy dog
fox dog

the result is:

$ sed '/fox/{
    s/fox//g
    r f.html
}' file.txt
the
quick
brown

    </div>
  </div>
  <br>
  <div id="container2">
    <div class="question" onclick="javascript:show('answer2')";>
jumps
over
the lazy dog
 dog
    </div>
  </div>
  <br>
  <div id="container2">
    <div class="question" onclick="javascript:show('answer2')";>

EDIT: to alter the file being processed, just pass the -i flag to sed:

sed -i '/fox/{
    s/fox//g
    r f.html
}' file.txt

Some sed versions (such as my own one) require you to pass an extension to the -i flag, which will be the extension of a backup file with the old content of the file:

sed -i.bkp '/fox/{
    s/fox//g
    r f.html
}' file.txt

And here is the same thing as a one liner, which is also compatible with Makefile

sed -i -e '/fox/{r f.html' -e 'd}'
SleepyCal
  • 5,739
  • 5
  • 33
  • 47
brandizzi
  • 26,083
  • 8
  • 103
  • 158
  • 1
    This totally works! Give this man the medal of honour! One last thingr Brandizzi... this is printing to the console, but not to the file. Could we get a bit of code to do that? Thanks a million! – Eric Brotto Jul 22 '11 at 13:57
  • Brandizzi. Getting some strange behaviour. Could you check my Edit 1? – Eric Brotto Jul 22 '11 at 14:10
  • An example with perl would be nice also, as sed is a PITA in OSX. – Nick Feb 21 '13 at 18:27
  • 4
    Your results highlight a curiousity of an extra blank line being added at the start of the replacement, trying to figure out how to eliminate that. – Eddie Jul 16 '13 at 14:25
  • 1
    Amazing: thx @brandizzi. I add that double-quotes are clearly to be used if patterns and/or replacements are from $variables. Also beware to [correctly escape](http://backreference.org/2009/12/09/using-shell-variables-in-sed) "fox". – Campa Feb 25 '14 at 11:23
  • 3
    You totally rock. I opted for the one liner, but I had to separate the `d` command (at least on macOS): `sed -i -e '/fox/{r f.html' -e 'd' -e '}' file.txt` – Ryan McGeary Jan 11 '18 at 21:36
  • 4
    this takes the whole line instead of just the text I match on. – Vincent Gerris Sep 30 '20 at 09:35
12

Ultimately what I went with which is a lot simpler than a lot of solutions I found online:

str=xxxx
sed -e "/$str/r FileB" -e "/$str/d" FileA

Supports templating like so:

str=xxxx
sed -e "/$str/r $fileToInsert" -e "/$str/d" $fileToModify
buddyp450
  • 528
  • 2
  • 10
  • 27
  • 5
    this doesn't work in case the matched str is not all on single line. This would replace the entire line with the contents of fileToInsert even if a part of the string matched – saGii Apr 09 '17 at 00:30
  • indeed, any idea how to improve on that ? – Vincent Gerris Sep 30 '20 at 09:35
  • I ended up with : KEY=$(cat /app/certs/firestore-stt.pem); awk -v file="$KEY" 'BEGIN{}/\{PRIVATE_KEY\}/{gsub("\{PRIVATE_KEY\}",file)}1' storeKey.json > temp.txt && mv temp.txt fstoreKey.json . might be improvable but does the job for a pem file with newlines (because sed with r option always replaces whole line). – Vincent Gerris Sep 30 '20 at 12:50
0

Another method (minor variation to other solutions):

If your filenames are also variable ( e.g. $file is f.html and the file you are updating is $targetfile): sed -e "/fox/ {" -e "r $file" -e "d" -e "}" -i "$targetFile"

Piotr Siupa
  • 3,929
  • 2
  • 29
  • 65
Isaac
  • 11
  • 6
  • It looks like an awkward attempt to pack the accepted solutions into a single line. I don't know sed that well but I believe you can use `;` instead of `" -e "`. – Piotr Siupa Sep 04 '22 at 11:50