4

Is there a way to use sed to substitute any string for any other string? Because sed uses a delimiter character for the find and replace expression, I can't figure out a way to write a sed command capable of substituting a string with potentially any character (or all characters) in any path for any other string (which may also contain any character).

Here is an example of what I have that does not work:

new_value="foobar"
old_value="baz"
echo "$some_path" | sed -e "s|$old_value|$new_value|"

This works unless $new_value or $old_value contains a pipe, in which case the command is invalid because the substitution syntax is broken by the variables used in the sed expression.

Is there a way to use sed to substitute any string for any other string?

If not, is there a Unix good alternative?

2
  • 1
  • Thanks @RakeshSharma. You are right. That is what I need. The answers here are not correct. Do you recommend using | or / as the delimiter in the find and replace command? I figured | might be easier as paths will contain /.
    – Stratus3D
    Jan 1, 2020 at 15:28

2 Answers 2

4

A simple way around this is to escape everything in your variables before calling sed:

new_value="foo|bar"
old_value="ba|z"
new_value=$(printf '%q' "$new_value")
old_value=$(printf '%q' "$old_value")
some_path="/path/to/ba|z/file"

And then:

$ echo "$some_path" | sed -e "s|$old_value|$new_value|"
/path/to/foo|bar/file

The trick here is the printf '%q'. From help printf (showing the help of bash's builtin printf):

  %q    quote the argument in a way that can be reused as shell input
5
  • 2
    But we can't do this blindly, for there are some characters that take on special meaning when escaped, like < Dec 10, 2019 at 16:47
  • @RakeshSharma oh! That's a very good point, I hadn't considered \> and \<. Those can indeed cause issues.
    – terdon
    Dec 10, 2019 at 16:50
  • 1
    ( )also take on special meaning when escaped, they become registers. Dec 10, 2019 at 16:54
  • @RakeshSharma true, but that's easier to avoid: just use sed - E.
    – terdon
    Dec 10, 2019 at 18:19
  • I m assuming Posix sed. And whatever option we choose, doing an escape of all characters is just not done. Dec 11, 2019 at 1:29
1

you can use shell paramater substitution to escape the needed char:

sed -e "s|${old_value//|/\\|}|${new_value//|/\\|}|"
7
  • 1
    The same applies to your way as well. Dec 10, 2019 at 16:48
  • @RakeshSharma the same what?
    – terdon
    Dec 10, 2019 at 16:49
  • The same incorrect way to escape en masse. Dec 10, 2019 at 16:55
  • 1
    What if the input on lhs had the string abc{2} then the escaping will change the very nature of the regex. Dec 10, 2019 at 16:59
  • 1
    The OP wanted any character to be handled and not just the pipe. Dec 11, 2019 at 1:23

You must log in to answer this question.

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