52

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
markling
  • 1,232
  • 1
  • 15
  • 28
Geo
  • 93,257
  • 117
  • 344
  • 520
  • It doesn't. Show us why you think it does. – Ignacio Vazquez-Abrams Mar 03 '10 at 07:01
  • is your shell consuming an extra level of backslashing? – p00ya Mar 03 '10 at 07:07
  • 5
    one \ for the shell, one \ for the sed, one \ for the backslash = \\\ – Kimvais Mar 03 '10 at 07:24
  • @Kimvais: If it was as you stated there, it'd be four, as sed requires an escaped backslash (2) and the shell escaping of those would require one each. –  Mar 03 '10 at 07:26
  • Use single quotes for `sed` and you can get away with two backslashes. `echo "sample_input\whatever" | sed 's/\\/\//'` Hopefully someone will come up with the correct explanation for this behavior. – Amarghosh Mar 03 '10 at 08:06
  • @Amarghosh nope, that is not the case for win xp cmd.exe and sed from msys-1.0. I get the exact error as in the question and I used single quotes. – panny Feb 13 '13 at 15:27
  • You even need **four backslashes** and two quotes like in `sed "s/.*/\\\\""/"` to print out a single backslash followed by a quote `\"`. – Doomjunky Aug 01 '17 at 11:57
  • sorry for my question but you want to replace backslash with a slash? – Timo Jan 16 '18 at 13:56
  • It's because you use double quotes therefore the string is interpolated. See this [question](https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash). Using single quotes, this works for me in bash: `sed 's/\///'` – smac89 Mar 27 '21 at 08:56

7 Answers7

52

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

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
14

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.

7

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

Community
  • 1
  • 1
MS.Kim
  • 219
  • 2
  • 4
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"
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
2

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

James K
  • 21
  • 1
0

Replacing one backslash with two on my Cygwin requires this expression:

sed -e "s|\\|\\\\|g"

OutputLogic
  • 386
  • 4
  • 11
0

I guess, you assuming \\\n or \\\t as three backslashes there, but actually, its 2 backslashes and another patterns

   backslash          \\
   newline            \n
   tab                \t

also, / might need to escape because in s/.../, / is using for open and close parts.

so /\\\/\// would be \\ + \/ + \/ according to your updated example

YOU
  • 120,166
  • 34
  • 186
  • 219
  • I like your method in explaining, could you please take a look at this and try to answer it? https://superuser.com/questions/1249497/sed-needs-n-to-append-new-line?noredirect=1#comment1834908_1249497 – Mohammed Noureldin Sep 12 '17 at 19:42