Is a sub-shell the same thing as a child-shell
A subshell duplicates the existing shell. It has the same variables¹, the same functions, the same options, etc. Under the hood, a subshell is created with the
fork system call²; the child process goes on to do what is expected of it while the parent waits (e.g.,
$(…)) or goes on with its life (e.g.,
… &) or otherwise does what is expected of it (e.g.,
… | …).
sh -c … does not create a subshell. It launches another program. That program happens to be a shell, but that's just a coincidence. The program may even be a different shell (e.g., if you run
sh -c … from bash, and
sh is dash), i.e., a completely different program that just happens to have significant similarities in its behavior. Under the hood, launching an external command (
sh or any other) calls the
fork system call and then the
execve system call to replace the shell program in the subprocess by another program (here
$$, but excluding some shell-specific variables such as bash and mksh's
² At least, that's the traditional and usual implementation. Shells can optimize the fork away if they can mimic the behavior otherwise.
Relevant man pages: fork(2), execve(2).
A sub-shell environment does not need to live in a separate process, it just needs to duplicate the current execution environment. In
ksh93 this is done by a
virtual sub-shell mechanism that does not call
fork(). This makes ksh93 very fast on archaic platforms like
Win-DOS is extremely slow with forking.
sh -c cmd on the other side creates a new process with the default shell that does not need to be the same as your current interactive shell.
sh and your current shell are identical, this does not duplicate the execution environment and thus does not create a