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.
Your shell is interpreting the quotes, both '
and "
, before they even get to echo
. I generally just put double quotes around my argument to echo even if they're unnecessary; for example:
$ echo "Hello world"
Hello world
So in your first example, if you want to include literal quote marks in your output, they either need to be escaped:
$ echo \'Hello world\'
'Hello world'
Or they need to be used within a quoted argument already (but it can't be the same kind of quote, or you'll need to escape it anyway):
$ echo "'Hello world'"
'Hello world'
$ echo '"Hello world"'
"Hello world"
In your second example, you're running a command substitution in the middle of the string:
grep $ARG /var/tmp/setfile | awk {print $2}
Things that start with $
are also handled specially by the shell -- it treats them as variables and replaces them with their values. Since most likely neither of those variables are set in your shell, it actually just runs
grep /var/tmp/setfile | awk {print}
Since grep
only sees one argument, it assumes that argument is the pattern you're searching for, and that the place it should read data from is stdin, so it blocks waiting for input. That's why your second command appears to just hang.
This won't happen if you single-quote the argument (which is why your first example nearly worked), so this is one way to get the output you want:
echo \'' echo PARAM=` grep $ARG /var/tmp/setfile | awk '{print $2}' ` '\'
You can also double-quote it, but then you'll need to escape the $
s so the shell doesn't resolve them as variables, and the backticks so the shell doesn't run the command substitution right away:
echo "' echo PARAM=\` grep \$ARG /var/tmp/setfile | awk '{print \$2}' \` '"
Best Answer
From
man sh
It means your command should be like this:
Similarly:
That was the first part to understand; the second case is simple and doesn't need explanation, I guess.