Search code examples
cprocesspopenexecl

Why should one exec "sh -c a.out" instead of a.out itself?


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?


Solution

  • Why would you want to (or should you) exec an executable, e.g. a.out via sh -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 just a.out itself, does the actual a.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.