A shell, typically parse a command, then fork (duplicates itself).
The duplicated process replaces itself using Execvp by the program described in the command
The other process wait for the duplicated one to exit using waitpid. When that happens it prints the prompt again, ready for the next one to come. And the whole thing restarts again.
Not a very hard life.
Here are the important parts of the manpages of the 3 functions :
fork – create a child process
fork() creates a new process by duplicating the calling process. The
new process is referred to as the child process. The calling process
is referred to as the parent process.
The child process and the parent process run in separate memory spaces.
At the time of fork() both memory spaces have the same content.
On success, the PID of the child process is returned in the parent, and
0 is returned in the child. On failure, -1 is returned in the parent,
no child process is created, and errno is set appropriately.
EXEC(3) Linux Programmer’s Manual EXEC(3)
execvp – execute a file
int execvp(const char *file, char *const argv);
The execvp() function replaces the current process image with
a new process image.
The initial argument for this function is the name of a file that is
to be executed.
The const char *arg can be thought of as arg0, arg1, …, argn.
Together they describe a list of one or more pointers to null-termi‐
nated strings that represent the argument list available to the exe‐
cuted program. The first argument, by convention, should point to the
filename associated with the file being executed. The list of argu‐
ments must be terminated by a null pointer, and, since these are vari‐
adic functions, this pointer must be cast (char *) NULL.
The exec() functions return only if an error has occurred. The return
value is -1, and errno is set to indicate the error.
waitpid – wait for process to change state
pid_t waitpid(pid_t pid, int *status, int options);
The waitpid() system call suspends execution of the calling process
until a child specified by pid argument has changed state. By default,
waitpid() waits only for terminated children.