I'm studying Apple's implementation of popen()
at https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/popen.c.auto.html and noticed that they do execl(_PATH_BSHELL, "sh", "-c", command, NULL)
instead of execl(_PATH_BSHELL, command, NULL)
.
Why would you want to (or should you) exec an executable, e.g. a.out
via sh -c
instead of just the executable itself?
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?
Why would you want to (or should you) exec an executable, e.g.
a.out
viash -c
instead of just the executable itself?
popen()
is designed to run shell commands that include shell syntax like >
redirection, |
pipes, and &&
command chaining. It needs to pass the string through sh -c
in order to support those constructs. If it didn't those syntactical features would be passed verbatim to the program in question as arguments.
For example, popen("make clean && make")
should trigger two make
invocations. Without sh -c
it would call make
once with three arguments, as if one had typed
$ make clean '&&' make
at the terminal.
If you exec
sh -c a.out
instead of justa.out
itself, does the actuala.out
process end up being a "grandchild" process and not a child process?
Yes, that is correct. There will be a sh
process in between the current process and a.out
.