7

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

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

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
    
  • 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 '17 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 '17 at 18:45
  • @James I added examples with different quotation to the answer, it may be useful. – jimmij Jul 19 '17 at 19:06
5

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.

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

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.