28

I have the following string: /tmp/test/folder1/test.txt

I wish to use sed to substitute / for \/ - for example:

\/tmp\/test\/folder1\/test.txt

So I issue:

echo "/tmp/test/folder1/test.txt" | sed "s/\//\\\\//g"

Although it returns:

sed: -e expression #1, char 9: unknown option to `s'

I am escaping the forward slash and backslash - so not sure where I have gone wrong here

2
  • Do you want to substitute / for \/ (so replace all \/ with /) or do you want to substitute \/ for / (replace all / with \/)?
    – terdon
    Jul 19, 2017 at 16:02
  • 1
    @James you could use different delimiter in sed command, like sed 's:something:toSomethingElse:' Jul 19, 2017 at 16:20

3 Answers 3

57

You need to escape (with backslash \) all substituted slashes / and all backslashes \ separately, so:

$ echo "/tmp/test/folder1/test.txt" | sed 's/\//\\\//g'
\/tmp\/test\/folder1\/test.txt

but that's rather unreadable.

However, sed allows to use almost any character as a separator instead of /, this is especially useful when one wants to substitute slash / itself, as in your case, so using for example semicolon ; as separator the command would become simpler:

echo "/tmp/test/folder1/test.txt" | sed 's;/;\\/;g'

Other cases:

  • If one wants to stick with slash as a separator and use double quotes then all escaped backslashes have to be escaped one more time to preserve their literal values:

    echo "/tmp/test/folder1/test.txt" | sed "s/\//\\\\\//g"
    
  • if one doesn't want quotes at all then yet another backslash is needed:

    echo "/tmp/test/folder1/test.txt" | sed s/\\//\\\\\\//g
    
4
  • Thanks I also noticed you are using single quotes - since I presume double quotes would not preserve the literal value of the '\' character.
    – James
    Jul 19, 2017 at 18:39
  • @James yes, everything inside single quotes is treated literally by shell and as that passed to sed. Inside double quotes some characters are expanded, and even whole expressions could be evaluated by shell.
    – jimmij
    Jul 19, 2017 at 18:45
  • @James I added examples with different quotation to the answer, it may be useful.
    – jimmij
    Jul 19, 2017 at 19:06
  • Thanks! I realised that having / is a bad idea when your data contains / - simple, but subtle. Often, you need to take a step back and think about the problem.
    – Nishant
    Aug 16, 2022 at 7:01
9

Or, if the value is in a (bash) shell variable:

var=/tmp/test/folder1/test.txt
$ echo "${var//\//\\\/}"
\/tmp\/test\/folder1\/test.txt

The first // start parameter expansion, saying to replace all matches with the replacement. The next \/ is the escaped / to match, and the \\\/ is an escaped \ followed by an escaped / as the replacement.

1
  • Other forms of quoting (beside backslash) may be used. Try echo "${var//'/'/'\/'}" (since bash 4.3)
    – user232326
    Jul 20, 2017 at 4:28
3

The final solution will be this one:

$ sed 's:/:\\/:g'  <<<"$str"
\/tmp\/test\/folder1\/test.txt

But to explain how to get there:
Yes, you were missing one backslash:

$ str='/tmp/test/folder1/test.txt'
$ sed "s/\//\\\\\//g" <<<"$str"
\/tmp\/test\/folder1\/test.txt

I hope that one space will make it clear:

$ sed "s/\//\\\\ \//g"  <<<"$str"
\ /tmp\ /test\ /folder1\ /test.txt

But, if you were to change the sed delimiter to : (for example):

$  sed "s:\/:\\\\\/:g"  <<<"$str"
\/tmp\/test\/folder1\/test.txt

But that is not strictly correct as the (now not special) / does not need scaping:

$ sed "s:/:\\\\/:g"  <<<"$str"
\/tmp\/test\/folder1\/test.txt

And, if you were to use single quotes instead of double quotes the shell will not change double \\ to one, so less \ will be correct:

$ sed 's:/:\\/:g'  <<<"$str"
\/tmp\/test\/folder1\/test.txt

Which is quite cleaner.

0

You must log in to answer this question.

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