0

I have several files that all contain a string. This string needs to be replaced by the whole content of another file (that can possibly be multi-line). How can I do this?

What I need is something like sed -i 's/string/filename/' * where filename is an actual file and not the string "filename".

Additional info: The file can contain special characters such as / or \ or | or [ or ].

3

3 Answers 3

2

bash works well for this:

$ cat replace
foo/bar\baz
the second line

$ cat file
the replacement string goes >>here<<

$ repl=$(<replace)

$ str="here"

$ while IFS= read -r line; do
    echo "${line//$str/$repl}"
done < file
the replacement string goes >>foo/bar\baz
the second line<<

Awk would work, except that it will interpret backslash escapes (the \b in my example)

$ awk -v string="here" -v replacement="$(<replace)" '
    {gsub(string, replacement); print}
' file
the replacement string goes >>foo/baaz
the second line<<
1
  • For my intented use case the bash version works best and is the most flexible. Thanks. :)
    – Foo Bar
    Commented Jun 27, 2015 at 8:34
2

You need the underused sed command r which reads a file:

sed -i '/string/{r filename
                 d}'

I assume you want to replace the whole line, else replace d by something suitable.

5
  • 1
    else there is nothing suitable as r always inserts a newline before the ouput of a read Commented Jun 26, 2015 at 16:25
  • correct: r ignores the pattern space, but you can remove the d and do (eg) s/string/something else/. This changed line will appear before the file contents.
    – meuh
    Commented Jun 26, 2015 at 16:34
  • 1
    The point was that you cannot insert the content of another file inline if you use r , no matter what you do. Commented Jun 26, 2015 at 16:37
  • gotcha. Might be adequate for the OP though.
    – meuh
    Commented Jun 26, 2015 at 17:02
  • The bash version from the accepted answer works best for me. Nevertheless, a +1 for you because I did not know about sed's r.
    – Foo Bar
    Commented Jun 27, 2015 at 8:36
0

I got this to work:

$ foo='baz'
$ echo "foobarbaz" | sed "s/foo/${foo}/"
bazbarbaz

Taking that one step further, your first line would be something like:

$ foo=`cat filename`

This assumes you know the filename before you reach the line to be replaced, of course - if you don't, you have to read the line, get the filename, then do the read-and-replace.

5
  • Will this work without checking for escape characters or escaping control characters? Example: the file contains the character /.
    – Foo Bar
    Commented Jun 26, 2015 at 13:51
  • I honestly don't know, but given how often I run in to that problem, I'm going to bet it won't.
    – John
    Commented Jun 26, 2015 at 13:53
  • Actually, it might: foo="baz\bak" followed by the echo | sed works.
    – John
    Commented Jun 26, 2015 at 13:55
  • sed will complain if $foo contains the delimiter for the s/// command Commented Jun 26, 2015 at 14:41
  • 1
    ...not to mention that if the replacement file has more than one line then s/../../ won't work anyway... Commented Jun 26, 2015 at 16:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .