0

I need to modify some Windows paths.

For instance,

D:\usr

to

D:\first\usr

So, I have created a variable.

$path = "first\usr"

then used the following command:

sed -i -e 's!\\usr!${path}/g;' test.txt

However, this ends up with the following:

D:\firstSr

How do I escape \u in sed?

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
code_seeker
  • 112
  • 2
  • 12
  • possible duplicate of [Why does sed require 3 backslashes for a regular backslash?](http://stackoverflow.com/questions/2369314/why-does-sed-require-3-backslashes-for-a-regular-backslash) – Risadinha Jul 15 '15 at 12:32
  • you need to double escape the content of new value also, not only the sed search pattern – NeronLeVelu Jul 15 '15 at 12:35
  • What shell or scripting language are you using? `$path = "first\usr"` looks like Perl, but the rest doesn't... – Toby Speight Feb 22 '16 at 11:51

2 Answers2

2

Assuming your path variable was assigned properly (without spaces in the assignment: path='first\usr'), fixing step by step for an input file test.txt with one example path:

$ cat test.txt
D:\usr
  1. Your original command

    $ sed 's!\\usr!${path}/g;' test.txt
    sed: -e expression #1, char 18: unterminated `s' command
    

    doesn't do much, as you've mixed ! and / as the delimiter.

  2. Fixing delimiters:

    $ sed 's!\\usr!${path}!g;' test.txt
    D:${path}
    

    Now no interpolation happens at all because of the single quotes. I suspect these are just copy-paste mistakes, as you obviously got some output.

  3. Double quotes:

    $ sed "s!\\usr!${path}!g" test.txt
    bash: !\\usr!${path}!g: event not found
    

    Now this clashes with history expansion. We could escape the !, or use a different delimiter.

  4. / as delimiter:

    $ sed "s/\\usr/${path}/g" test.txt
    D:\firstSr
    

    Now we're where the question actually started. ${path} expands to first\usr, but \u has a special meaning in GNU sed in the replacement string: it uppercases the following character, hence the S.

    Even without the special meaning, \u would most likely just expand to u and the backslash would be gone.

  5. Escaping the backslash:

    $ path='first\\usr'
    $ sed "s/\\usr/${path}/g" test.txt
    D:\first\usr
    

    This works.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
0

Depending on which shell you are using, you may be able to use parameter expansion to double \ in your substitution string and prevent the \u interpretation:

path="first\usr"
sed -e "s/\\usr/${path//\\/\\\\}/g" <<< "D:\usr"

The syntax for replacing a pattern with the shell parameter expansion is ${parameter/pattern/string} (one replacement) or ${parameter//pattern/string} (replace all matches).

This substitution is not specified by POSIX, but is available in Bash.

Where it is not available, you may need to filter $path through a process:

path=$(echo "$path" | sed 's/[][\\*.%$]/\\&/g')

(N.B. I have also quoted other sed metacharacters in this filter).

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
SLePort
  • 15,211
  • 3
  • 34
  • 44