The Brain Transplant
If fork() only creates clones, how do we ever run different programs? We don't want thousands of copies of the shell.
This is where the exec() family of system calls comes in. Immediately after forking, the child process typically calls exec() to replace itself with an entirely different program.
When a process calls exec():
- The kernel discards the process's current code, stack, heap, and data segments.
- It loads the new program's binary from disk into the process's address space.
- Execution begins at the new program's entry point (its
main()function).
The process's PID does not change. The container (the process identity, open file descriptors, environment variables) persists — only the contents are replaced.
The fork-exec pattern is the universal mechanism behind every command you run in a shell:
- You type
ls -lain bash. - Bash calls
fork()— a child bash process is created. - The child calls
exec("/bin/ls", ["ls", "-la"])— the child transforms intols. lsruns, prints output, and exits.- Bash (the parent) calls
wait()to collect the exit status and prints the next prompt.
The Analogy:
fork()is like building a brand-new, identical factory next to the original.exec()is like gutting that new factory — removing all the old machinery and workers — and installing completely new equipment to manufacture a different product, all within the same building shell (same PID, same file descriptors).
Interviewers frequently ask: "How does a shell execute a command?" The answer is always fork-exec: the shell forks a child, the child execs the target binary, and the parent waits. A common follow-up is: "Why fork first instead of just exec directly?" Because exec replaces the current process — if the shell exec'd directly, the shell itself would be replaced and you'd lose your terminal session.