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.

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 ?

share|improve this question
2  
Use printf, echo isn't portable in the regard. –  jordanm Mar 28 '13 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) –  Olivier Dulac Mar 28 '13 at 19:11
2  
Your function used '$s\n' when it should have used '%s\n'. –  cjm Mar 29 '13 at 6:25

3 Answers 3

up vote 6 down vote accepted

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), so:

$ foo '\\foo\bar'

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

share|improve this answer
    
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? –  user815423426 Mar 29 '13 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. –  Stéphane Chazelas Mar 29 '13 at 8:00

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 
\\here\is\some\path
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)

share|improve this answer
    
Thanks but as I mentioned in the title: I want to avoid escaping backslashes. –  user815423426 Mar 28 '13 at 19:00
    
oops, I'll edit ^^ –  Olivier Dulac Mar 28 '13 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) –  user815423426 Mar 28 '13 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. –  Olivier Dulac Mar 28 '13 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. –  Olivier Dulac Mar 29 '13 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.

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.