goat goat - 5 months ago 12
Bash Question

bash subshell command execution order with su

Normally I expect bash to execute commands in order when separated by a semicolon

eg, cmd1 executes before cmd2 in:

cmd1;cmd2


But I've come across a scenario where this doesn't hold true.

echo 'my password' | sudo -S su -c "echo a 1>&2 ; $(echo b 1>&2)" root


I would expect the output to be

a
b


but it's actually

b
a


Why?

Is this something to do with the c flag for the su command? It only seems to occur when I put the 2nd command in a subshell.

Note that the IO redirection isn't the culprit - I added that in only to make an easy way to demonstrate my issue. If you put different commands there, like a
cd
, and a
stat
, you'll see they're really executed out of order.

Answer
$ echo "hello $(echo world)"
hello world

$( ... ) runs the command inside and substitutes the collected output, i.e. the command above ends up running echo "hello world".

Similarly,

sudo -S su -c "echo a 1>&2 ; $(echo b)"

would end up running

sudo -S su -c "echo a 1>&2 ; b"

But with $(echo b 1>&2) the command writes b to stderr (and nothing to stdout), so while the shell is processing the string you see b appearing on the screen, and then the whole $( ... ) construct is replaced by nothing (because it writes nothing to stdout).

What ends up running is

sudo -S su -c "echo a 1>&2 ; " root

If all you want to do is run a command in a subshell, that's ( ... ), not $( ... ).

Comments