UNIX compliant implementations of echo
are required to output -e<space>hello<newline>world<newline>
there.
Those that don't are not compliant. Many aren't which means it's almost impossible to use echo
portably, printf
should be used instead. bash
's echo
, in some (most) builds of it, is only compliant when you enable both the posix
and xpg_echo
options. That might be the echo
behaviour you were expecting.
Same for the echo
standalone utility that comes with GNU coreutils
which is only compliant if it's invoked with $POSIXLY_CORRECT
set in its environment (and is of a recent enough version).
make
normally runs sh
to interpret the command lines on each action line.
However, the GNU implementation of make
, as an optimisation, can run commands directly if the code is simple enough and it thinks it doesn't need to invoke a shell to interpret it.
That explains why echo --version
gives you /bin/echo
, but echo ... > file
needs a shell to perform the redirection.
You can use strace -fe execve make
to see what make
executes (or the truss
/tusc
... equivalent on your system if not Linux).
Here, it seems that while your /bin/echo
is not compliant, your sh
has a echo
builtin that is compliant.
Here, use printf
if you want to expand echo
-style escape sequences:
printf '%b\n' 'hello\nworld'
In its format argument, printf
understands C-style escape sequences (there's a difference with the echo-style ones for the \0xxx
(echo) vs \xxx
(C) octal sequences)
printf 'hello\nworld\n'
Here, you could also do:
printf '%s\n' hello world
Which is the common and portable way to output several arguments on separate lines.
Another approach would be to add:
SHELL = bash
To your Makefile
for make
to invoke bash
(assuming it's installed and found in $PATH
) instead of sh
to interpret the command lines. Or invoke make
as make <target> SHELL=bash
.
That won't necessarily make it more portable as while there are more and more systems where bash
is installed by default these days, there are some (like on Solaris) where bash
is built so that its echo
builtin behaves the standard way by default.
Setting SHELL
to anything other than /bin/sh
also has the side effect of disabling GNU make
's optimisation mentioned above, so with make <target> SHELL=sh
or make <target> SHELL=/bin//sh
, you'd get consistent behaviours between the two invocation, while still not having to add a dependency to bash.