Why is echo "bar" -n different from echo -n "bar"?
As most others have observed, "-n" is interpreted literally if placed anywhere but immediately after the echo
command.
Historically, UNIX utilities were all like this -- they looked for options only immediately after the command name. It was likely either BSD or GNU who pioneered the more flexible style (though I could be wrong), as even now POSIX specifies the old way as correct (see Guideline 9, and also man 3 getopt
on a Linux system). Anyway, even though most Linux utilities these days use the new style, there are some holdouts like echo
.
Echo
is a mess, standards-wise, in that there were at least two fundamentally conflicting versions in play by the time POSIX came into being. On the one hand, you have SYSV-style, which interprets backslash-escaped characters but otherwise treats its arguments literally, accepting no options. On the other, you have BSD-style, which treats an initial -n
as a special case and outputs absolutely everything else literally. And since echo
is so convenient, you have thousands of shell scripts that depend on one behavior or the other:
echo Usage: my_awesome_script '[-a]' '[-b]' '[-c]' '[-n]'
echo -a does a thing.
echo -b does something else.
echo -c makes sure -a works right.
echo -- DON\'T USE -n -- it\'s not finished! --
Because of the "treat everything literally" semantic, it's impossible to even add a new option to echo
without breaking things. If GNU used the flexible options scheme on it, hell would break loose.
Incidentally, for best compatibility between Bourne shell implementations, use printf
rather than echo
.
UPDATED to explain why echo
in particular does not use flexible options.
The other answers get to the point that you can look at the man page to see that -n is becoming part of the string to echo. However I just want to point out that it's easy to investigate this without the md5sum and makes what's going on a little less cryptic.
[11:07:44][dasonk@Chloe:~]: echo -n "bar"
bar[11:07:48][dasonk@Chloe:~]: echo "bar" -n
bar -n
Wow, everyone's explanations are lengthy.
It's this simple:
-n
is an option if it appears before the string, otherwise it's just another string to be echoed.
Remove the | md5sum
and you'll see the output is different.