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.

Compare

echo -n "bar"

with

echo "bar" -n

The former does what I think it's supposed to do (prints "bar" without a newline), while the latter doesn't. Is this a bug or by design? Why is it different than many cli programs in that you can't move the options around? For example, tail -f /var/log/messages is exactly the same as tail /var/log/messages -f. I sometimes do the latter when I forget I wanted the former, because internally the options and arguments are rearranged, usually by getopt.

Update: yes I originally nerf-ed my question. I removed the nerf you'll have to view history to make some of the answers make sense.

share|improve this question
3  
From what I see, the difference is immediately obvious. echo -n "bar" gives "bar", while echo "bar" -n gives "bar -n" –  phunehehe Jan 20 '11 at 5:42
add comment

4 Answers 4

up vote 18 down vote accepted

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.

share|improve this answer
    
upvote since you're the only one to mention that's the expected getopt behavior. –  Geoffrey Bachelet Jan 20 '11 at 8:41
    
@jander why is echo a "holdout"? I think it's a gnu coreutil? –  xenoterracide Jan 20 '11 at 10:25
    
@xeno: I've updated my answer. Basically, GNU didn't want to break things. –  Jander Jan 20 '11 at 16:16
1  
Accepting options after the first non-option is specific to GNU utilities and program using GNU libc's getopt facilities. The user can always get backward-compatible behavior by setting the environment variable POSIXLY_CORRECT. –  Gilles Jan 20 '11 at 21:29
1  
For the specific case of echo, there are also implementations that recognize -e or -E as options. For portability, don't start with a - or use something like printf %s -e. –  Gilles Jan 20 '11 at 21:30
show 1 more comment

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
share|improve this answer
3  
+1 exactly. If a pipeline isn't doing what you expect, test each part separately. –  Mikel Jan 20 '11 at 5:20
add comment

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.

share|improve this answer
add comment

From simple inspection, this is not a bug by design...

echo "bar" -n | md5sum

a3f8efa5dd10e90aee0963052e3650a1

Try this command for yourself:

echo "bar -n" | md5sum

You will notice that the resulting md5 is

a3f8efa5dd10e90aee0963052e3650a1

You just mixed-up the use of -n in echo.

In your first sample code

echo -n "bar" | md5sum

-n is used to say DO NOT to put a newline after this echo.

Your second sample

echo "bar" -n | md5sum

is treating -n as a literal text.

Hope that explanation helps :)

Ismael Casimpan

share|improve this answer
add comment

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.