Bash – Treatment of backslashes across shells

bashquotingshellzsh

How do echo and printf treat backslashes in zsh, bash and other shells?

Under zsh I get the following behavior:

$ echo "foo\bar\baz"
foaaz
$ echo "foo\\bar\\baz"
foaaz
$ echo 'foo\bar\baz'
foaaz
$ echo 'foo\\bar\\baz'
foo\bar\baz

Under bash, things seem a bit more consistent:

bash$ echo "foo\bar\baz"
foo\bar\baz
bash$ echo 'foo\bar\baz'
foo\bar\baz
bash$

But more concretely: How can I pass a string containing backslashes such as \\foo\bar\something to:

  • echo
  • printf
  • print

and get exactly the same string? (in zsh and bash)?

Here is another experiment with functions in zsh:

function foo
{
    echo -E '$1'
}

$ foo \\here\is\some\path
$1

How can I have it just print \\here\is\some\path?

Update (Note: this has now been answered in Stephane's comment)

I have tried the following in zsh 5.0.2:

function foo
{
    printf '$s\n' $1 
}

foo '\\some\path'

But this prints $s ?

Best Answer

zsh echo behaves the standard way, like bash in UNIX mode. That is it expands \b to the ASCII BS character as the UNIX specification requires.

Don't use echo to display arbitrary strings, use printf:

printf '%s\n' "$1"

print -r -- "$1" also works but is ksh/zsh specific.

echo -E - "$1" work with zsh and I believe some BSDs.

cat << EOF
$1
EOF

works in any Bourne-like shell even those from a few decades when there was no printf command but it spawn a new process, and is really not necessary nowadays as we now have printf everywhere.

And by the way, you need to escape backslashes on a shell command line as it's special to the shell (every shell but rc), so:

$ foo '\\foo\bar'

foo \\foo\bar would pass the "\foo\bar" string to foo which can't reinvent the lost backslash back.

Related Question