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

Under zsh I get the following behavior:

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

Under bash, things seem a bit more consistent:

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

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

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 ?

  • 3
    Use printf, echo isn't portable in the regard.
    – jordanm
    Mar 28, 2013 at 18:54
  • you "foo" function : replace ' with " , and invoke it with : foo '\\here\is\some\path' (otherwise the invoking shell gets a chance to interpret the '\' before they get to the function) Mar 28, 2013 at 19:11
  • 2
    Your function used '$s\n' when it should have used '%s\n'.
    – cjm
    Mar 29, 2013 at 6:25

3 Answers 3


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

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.

  • Thanks Stephane. Oddly enough, the construction printf '%s\n' "$var" works for me on the command line (zsh 5.0.2, i.e. the latest), but not inside a function (see my update in the OP). Why? Mar 29, 2013 at 1:09
  • 1
    It's printf '%s\n', not printf '$s\n' you want. Note that you need to quote variables in other shells than zsh ("$1", not $1) and the standard function definition syntax is foo() { ...; }, though any shell but bash allow foo() any-command, and function foo { .... } is the ksh syntax. Mar 29, 2013 at 8:00
  • @Marcus, that's an answer to a different question. Apr 29, 2019 at 16:12
  • Why does this not work: printf 'C:\foo\bar.xml'.This works: echo -E 'C:\foo\bar.xml' - Why do you put the dash in echo -E -?
    – Timo
    Jan 26, 2021 at 18:52

new answer: read -r var

-r  raw input - disables interpretion of backslash escapes and line-continuation in the read data

and to display:

printf "%s" "$var"
echo "$var"

should work.

So for your foo function:

function foo
    read -r var
    echo -E "var is : ${var}"

$ foo 
var is : \\here\is\some\path

old answer below (not answering, but maybe usefull ^^)

just replace each \ by \\ to tell the shell "that it a literall \ I want". otherwise (for example in zsh, in your example) it could well be that \b means "1 backspace", or whatever.

you could for example use sed:

sed -e 's,\\,\\\\,g' < the_original > the_escaped_backslaches_version

(see how you also need to escape "\" there, to tell sed the same thing: "it is a literall "\" I want) (and notice I surround it by ' ' and not " " to avoid the shell to interpret most of it too)

  • Thanks but as I mentioned in the title: I want to avoid escaping backslashes. Mar 28, 2013 at 19:00
  • oops, I'll edit ^^ Mar 28, 2013 at 19:03
  • Thanks! But read -r var seems to wait for input from STDIN. What if I am passing it as an argument? (e.g. foo \\here\is\some\path) Mar 28, 2013 at 19:31
  • the shell IS interpreting backslashes. That's why you should probably move the argument passing to a read, see my "foo" example. Mar 28, 2013 at 19:33
  • 1
    iow: you want a "non-standard" handling of strings by the shell : you could more easily (and more extensively) have your program be compliant to what you want, instead of trying to have the shell-invoking-that-program to behave like you want. So: pass the args (the ones containing "\" that you don't want to escape) once the program is started, via "read -r", and not on its invoking shell command-line. Mar 29, 2013 at 10:00

Generally speaking you can't, because backslash is the escape character (and as such has to be escaped when its literal value is required). BASH provides single quotes for this purpose, however you can't use escape a single quote within single quoted string.

As for the echo discrepancy, it is a built-in an may behave differently across shells (to some degree). For example the BASH built-in has a -e option which tells it to interpret backslash sequences - with it you'd get the behaviour you saw in the Z shell.

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.