How a sub-shell differs from a sub-process/child-process can often be a cause for confusion. Hopefully, this article may help alleviate it.
A shell is just a program that interprets the commands entered into it and executes them. These commands are either built into the shell program or they are external programs which are invoked by the shell.
Built-in commands are those commands that are contained within the shell. They are part of the shell program. Depending on the shell, these built-in commands may vary. Here is a list of bash’s built in commands. type is a command that can used to find out if a command is a built-in or not.
A sub-process is created by the parent shell by making the system calls fork followed by exec. A sub-process executes independently of the parent process. Every command that is not a built-in command is just a script that is executed as a child-process by the parent shell. A child-process gets a copy of all of the environment variables of the parent shell. Environment variables are those variables that are declared with the export keyword. Please note that it is also possible to source a script into the parent shell. A sourced script is executed within the parent shell. No sub-process is created for it.
A sub-shell is a sub-process that is an almost identical copy of the parent shell. They get a copy of not just the environment variables but also the non-exported shell variables, functions etc. There are several ways to create a sub-shell. For example, any command within (…) is executed in a sub-shell. Each command in a pipeline is also executed in a sub-shell.
There are shells that may optimize out the creation of a sub-shell. ksh93 exhibits this behavior.