Bash – Why Does dash’s echo Expand \\ Differently?

bashdashechoquotingshell-script

I have a little open source project that for various reasons I've tried to write in reasonably portable shell script. Its automated integration tests check that hostile characters in path expressions are treated properly, among other things.

Users with /bin/sh provided by bash are seeing a failure in a test that I've simplified down to the following:

echo "A bug\\'s life"
echo "A bug\\\\'s life"

On bash, it produces this expected result:

A bug\'s life
A bug\\'s life

With dash, which I've developed against, it does this:

A bug\'s life
A bug\'s life

I'd like to think that I haven't found a bug in dash, that I might be missing something instead. Is there a rational explanation for this?

Best Answer

In

echo "A bug\\'s life"

Because those are double quotes, and \ is special inside double quotes, the first \ is understood by the shell as escaping/quoting the second \. So a A bug\'s life argument is being passed to echo.

echo "A bug\'s life"

Would have achieved exactly the same. ' being not special inside double quotes, the \ is not removed so it's the exact same argument that is passed to echo.

As explained at Why is printf better than echo?, there's a lot of variation between echo implementations.

In Unix-conformant implementations like dash's, \ is used to introduce escape sequences: \n for newline, \b for backspace, \0123 for octal sequences... and \\ for backslash itself.

Some (non-POSIX) ones require a -e option for that, or do it only when in conformance mode (like bash's when built with the right options like for the sh of OS/X or when called with SHELLOPTS=xpg_echo in the environment).

So in standard (Unix standard only; POSIX leaves the behaviour unspecified) echos,

echo '\\'

same as:

echo "\\\\"

outputs one backslash, while in bash when not in conformance mode:

echo '\\'

will output two backslashes.

Best it to avoid echo and use printf instead:

$ printf '%s\n' "A bug\'s life"
A bug\'s life

Which works the same in this instance in all printf implementations.

Related Question