Piping paths with different types of quotes for slash substitution

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

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

Second attempt:

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

Third attempt:

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

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)


Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

printf '%s\n' "$file" | tr -s '\\' /


setopt extendedglob
print -r -- ${file//\\##/\/}

Solution 2

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

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


Solution 3

You can just use the POSIX heredoc to do this:

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

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.

Solution 4

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.

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

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply