Why doesn't echo called as /bin/sh -c echo foo output anything?
From man sh
-c string If the -c option is present, then commands are read from string.
If there are arguments after the string, they are assigned to the
positional parameters, starting with $0
It means your command should be like this:
$ sh -c 'echo "$0"' foo
foo
Similarly:
$ sh -c 'echo "$0 $1"' foo bar
foo bar
That was the first part to understand; the second case is simple and doesn't need explanation, I guess.
$ echo foo
foo
This calls echo
with the argument foo and foo is printed.
$ /bin/sh -c echo foo
This invokes the shell with the argument echo
and provides foo as argument
$0
. The echo
outputs a new line and you discard the foo. If you want to
output foo, quote the argument:
sh -c 'echo foo'
or use the provided argument:
sh -c 'echo $0' foo
In this example
$ /bin/sh -c 'echo foo; echo bar'
foo
bar
The shell is invoked with the argument echo foo; echo bar
which outputs
foo
bar
In this command:
echo foo
echo
is the binary (or built-in command) and foo
is the first argument.
Here:
/bin/sh -c echo foo
/bin/sh
is the binary, whose first argument is -c
, which itself accepts a "command string" as parameter. This is echo
in the above example. Then there is a third argument: foo
which is an argument for /bin/sh
, not for echo
. That's why in your third example:
/bin/sh -c 'echo foo; echo bar'
... both are printed. You quoted the argument. Thus: the first argument is -c
, and the parameter to this argument is 'echo foo; echo bar'
which is interpreted whole as one argument; as the "command string".