Why does sed require 3 backslashes for a regular backslash?

I was able to reproduce this behavior using Vista and Cygwin 1.7.0.

  • Two backslashes produce the error
  • either three or four backslashes work
  • Five gives the same error

Two backslashes become a single backslash in the shell which then in sed escapes the forward slash which is the middle delimiter.

\\/ -> \/ (which makes the forward slash a regular character instead of a delimiter)

Three of them: The first two become one in the shell which then escape the third one in sed

\\\/ -> \\/

Four: Each pair become single ones in the shell then the first resulting one escapes the second in sed

\\\\/ -> \\/ 

Edit:

Oh, I forgot to say that both single quotes and double quotes worked the same for me (cmd.exe doesn't make the distinction that Bash, et al, makes).


Your shell (probably bash) is doing its own escaping, and that's confusing you. You can use an echo command to see what is being passed, or it's easy to write a custom program (commonly named "showargs" or similar):

$ echo "s/\\\/\//"
s/\\/\//
$ echo "s/\\/\//"
s/\/\//

You can also use single quotes, which are treated differently in bash.


That's due to sh's double-quoted string parsing rule.

Posix specifies how sh parses double-quoted strings.

The backslash shall retain its special meaning as an escape character (see Escape Character (Backslash)) only when followed by one of the following characters when considered special: $ ` " \

In other words, sh lefts the backslash which is followed by characters other than $ ' " .

So, if sh meets the double-quoted string sed "s/\\\/\//", sh parses it as follows.

  1. The first two \\ is changed into \. Because the first \ is followed by the second \.
  2. The third and fourth \ is still left in the string. Because both of them are followed by /, which is not special in double-quoted string.

After pasring, sh passes the string s/\\/\// to sed, which substitutes the first occurence of \ into /.

With same reasoning, when sh meets the string, "sed s/\\\\/\//", sh passes /\\/\// to sed, which also substitutes the first occurence of \ into /.


Please show an example of what you have in future. in sed, say you want to replace a "\" with pipe (|), for example

$ cat file
asklfja \ asf

$ sed 's/\\/|/g' file
asklfja | asf

$ sed 's%\\%|%g' file #using different delimiter
asklfja | asf

you just need to escape it once.

Edit: To @OP's example, since you are using cmd.exe and not bash/ksh, cmd.exe doesn't like single quotes. I cannot produce your scenario. This works for my GNU sed on windows using 2 slashes

eg

C:\test>echo "sample_input\whatever" | sed "s/\\/\//"
"sample_input/whatever"

Tags:

Regex

Sed