Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I would like to use sed to convert a path with backslashes to the same path with forward slashes:

E.g. I would like to pipe \\path\to\file\ and obtain /path/to/file

None of the following commands work, and I can't tell why:

First attempt:

> echo '\\path\to\file\' | sed 's/\\/\//g'
/path   o
         ile/

Second attempt:

echo \\path\to\file\ | sed 's/\\/\//g' 
/pathtofile

Third attempt:

 echo "\\path\to\file\" | sed 's/\\/\//g'
dbquote>

I get a similar behavior if I try piping to | tr '\' '/'

I am looking for the correct answer and, if possible, for an explanation of why none of the attempts above worked. Not sure if it matters, but this is all on zsh 4.2.6 (x86_64-redhat-linux-gnu)

Thanks!

share|improve this question
3  
I'd recommend using a different delimiter with sed than / when you're dealing with path delimiters. This works here with GNU sed in zsh: echo '\\path\to\file\' | sed -r 's:\\+:/:g'. –  Thor Sep 11 '12 at 14:23
    
What version of zsh are you using? –  Thor Sep 11 '12 at 14:24
    
@Thor, I just updated the OP to include the version –  user815423426 Sep 11 '12 at 14:26

4 Answers 4

up vote 5 down vote accepted
file='\\path\to\file\'
printf '%s\n' "$file" | tr -s '\\' /

zsh:

setopt extendedglob
print -r -- ${file//\\##/\/}
share|improve this answer

Don't use echo. The problem with echo is there are too many versions and each handles backslashes slightly differently. Yours is evidently interpreting the backslashes in your original string. If you just did

# first attempt
echo '\\path\to\file\'

I suspect you would see

\path   o
         ile\

Similarly in all your other attempts the problem is with your usage of echo and the interactions between echo and shell quoting and backslashes, and not with the second part of the pipe (the sed or tr).

The solution is to use printf instead - its behavior is much more consistent and portable since it is specified by POSIX.

printf '\\\\path\\to\\file\\\n'

gets you

\\path\to\file\
share|improve this answer
    
Thanks, do I need to add an extra backslash for each backslash for printf to work? It would be great to have a solution that directly works with paths "as they are typed in windows". –  user815423426 Sep 11 '12 at 14:19
    
I copy them from my local Windows OS onto a VNC session that is connected to a remote machine, but I get the same problem if I type the backslashes myself manually. –  user815423426 Sep 11 '12 at 14:25
    
I am hoping to write a zsh function that takes the windows path as an input argument and cds into that path on the remote filesystem (the function will have to change the anchor point and the backslashes to forward slashes to be able to cd into the folder) –  user815423426 Sep 11 '12 at 14:28
    
@roseck Sounds like a job for parameter expansion, not echo | sed. For example, try path='\\path\to\file'; printf 'cd'ing to %s\n' "${path//\\//}";. See also the X-Y Problem. –  jw013 Sep 11 '12 at 14:31

You can just use the POSIX heredoc to do this:

% sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<'_EOF_' 
> c:\some\stupid\windows\place
> _EOF_
/drive/c/some/stupid/windows/place

My answer to Is there a way to get actual uninterpreted shell arguments in a function describes this in more detail including how to dynamically read it into a shell variable via command substitution if necessary and pass it as an argument to a shell function.

In my answer to Quoting in ssh $host $FOO and ssh $host “sudo su user -c $FOO” type constructs I propose a perhaps different, and, as I believe, more straight-forward means of solving a problem that was otherwise excellently answered.

EDIT: I'm sorry, but I originally overlooked your request for "an explanation of why none of [your] attempts [at quoting backslashes as illustrated in your question] above worked:"

The trick to understanding the answer , while not actually very mysterious in its own right, is just, unfortunately, rather unintuitive. The primary barrier we generally encounter along these lines, or, at least, that I do, is that the shell is our default interface to the computer. As such, I think it can sometimes be difficult to remember that it is just a program; it is just an application like any other.

It might be a little easier to see through it if you switch the names of things around a little; don't call it the "shell", but try calling it instead the "command interpreter" (though shell would probably be fine as well if the word tended to inherit less jargonal connotation and its base meaning stood out a little better).

I find it easier to more correctly ascribe less control to the shell than I might otherwise do when it becomes, instead, just my interpreter. It's also in this way easier for me to remember that when it's involved it doesn't interpret only me, but also, true to its purpose and by its very nature, it attempts to middleman any conversation to which it is privy; if given the chance, the shell interprets other applications' data passed one to the other whether it needs to or not.

What I'm driving at is that the command interpreter naturally interprets by default all information passed to it into its own language, but its language is not necessarily any more correct in its own right than any other application's language. It is, of course, beneficial for other applications to speak well the language of the command interpreter, expediently saving them the trouble of interpreting you themselves, but they have just as much a right to try as it does as they are all just computer programs in the end.

Complicating matters for its sister applications, there is no single right or wrong way to interpret commands. The closest to correct where Unix is concerned (and therefore arguably at all) is probably the POSIX standard, but it certainly leaves some wiggle room for interpretation of interpretation (that was fun to say, and, as I hope, should probably illustrate my point). The result is a kind of digital language analogue to a human analog language's many dialects (also fun).

(Most of the above is just a primer, and is probably at least a little unnecessary to fully understand the following, but I'm hoping it will help.)

When we pass a command to the shell it iterates over a list of rules it is programmed to consider in a certain order to interpret our command before passing its interpretation of our command along as it has interpreted we intend it should. Our primary means of influencing which rules and in what order it considers them (other than the command itself, of course) are different types of shell quotes, among which is commonly included, as you have found, the \ backslash character.

Other applications have nearly as much cause and just as much a right to apply their own interpretive rule sets, but are little likely to have the chance before first the shell does, and so commonly their rules will be modeled after those of the shell. This can get complicated when they adopt the same quoting mechanics as the shell, because it leaves on us the onus (hehe) to \'"quote our quotes"\'. This complication can be frustratingly magnified when the shell and our target application differ only very little in quoting syntax, and we must indirectly address one through the other via minutely tedious instruction so that nothing is lost in translation.

My preferred means of handling such situations, as I demonstrated in my code block above, is just to directly instruct the shell where to stick it, so to speak, and that it should just pretty much ignore everything from <<'HERE' on because I think I can handle this conversation alone, thanks very much, and I'll be sure to let it know \nHERE\n when it should start paying attention again.

share|improve this answer

In bash, the first attempt works like a charm. It depends on what echo is and what version are you running. For instance, echo is a bash builtin and overrides the /bin/echo or /usr/bin/echo. Check man bash and info zsh to compare what options they accept and what the defaults are.

What you actually want is to force echo -E which disables escape sequence interpretation. It is default on bash but apparently not in zsh. You may also disable this particular builtin (I'm not using zsh so I don't know how), or use the most common way of handling this: call echo explicitly as /bin/echo.

Edit: of course you need single quotes, otherwise the shell will interpret the escape sequences before echo even has a chance.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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