Why does sed require 3 backslashes for a regular backslash?

I'm curious, why does sed need 3 \ just to recognize one? I'd understand it needing 2, but 3 I don't.

EDIT: here's an example on my Windows computer, using Cygwin:

$ echo "sample_input\whatever" | sed "s/\\\/\//"
sample_input/whatever

If I don't add 3 backslashes, I get a

sed: -e expression #1, char 7: unterminated s' command

Solution 1:

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).

Solution 2:

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.

Solution 3:

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 /.

Solution 4:

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"

Solution 5:

In my version of CYGWIN, it works as the original poster says, but, works differently (normally) if I use single quotes.

$ echo "sample_input\whatever" | sed 's/\\/\//'
sample_input/whatever
$ echo "sample_input\whatever" | sed "s/\\/\//"
sed: -e expression #1, char 7: unterminated `s' command

Hmmm..