that they do execl(_PATH_BSHELL, "sh", "-c", command, NULL)
instead of execl(_PATH_BSHELL, command, NULL)
The latter would NOT have executed command
directly, but _PATH_BSHELL
(/bin/sh
) with its $0
set to command
and no arguments, resulting in an shell expecting commands from its stdin.
Also, that syntax relies on NULL
being defined to an explicit pointer (e.g. ((void*)0)
), and not just 0
, which is not guaranteed anywhere. While they can do that in their implementation (because they control all the headers), it's not what you should do in application code.
And no, execl(command, command, (void*)NULL)
wouldn't have executed command
directly either, unless command
is a) a full path and b) in an executable format (binary or a script starting with a she-bang #!
-- the latter being a non-standard extension). If command
was a simple command name to be looked up in PATH
(like pwd
or a.out
) or an executable script not starting with a she-bang, you should've used execlp
instead of execl
.
The exec[lv]p[e]
functions do some of the things a shell does (like looking through the PATH
), but not all of them (like running multiple commands or expanding variables): that's why functions like system(3)
or popen(3)
pass the command to /bin/sh -c
. Notice that with both it's /bin/sh
, not the user's login shell or the $SHELL
from the environment which is used.
If you exec sh -c a.out
instead of just a.out
itself, does the actual a.out
process end up being a "grandchild" process and not a child process?
Only with some shells like dash
. Not with bash
, ksh93
, mksh
, zsh
, yash
, busybox
, etc, which will execute a.out
directly instead of forking and waiting for it.