[I'll repeat part of my answer from here.]
Why not just have a command that creates a new process from scratch? Isn't it absurd and inefficient to copy one that is only going to be replaced right away?
In fact, that would probably not be as efficient for a few reasons:
The "copy" produced by
fork() is a bit of an abstraction, since the kernel uses a copy-on-write system; all that really has to be created is a virtual memory map. If the copy then immediately calls
exec(), most of the data that would have been copied if it had been modified by the process's activity never actually has to be copied/created because the process doesn't do anything requiring its use.
Various significant aspects of the child process (e.g., its environment) do not have to be individually duplicated or set based on a complex analysis of the context, etc. They're just assumed to be the same as that of the calling process, and this is the fairly intuitive system we are familiar with.
To explain #1 a little further, memory which is "copied" but never subsequently accessed is never really copied, at least in most cases. An exception in this context might be if you forked a process, then had the parent process exit before the child replaced itself with
exec(). I say might because much of the parent could be cached if there is sufficient free memory, and I am not sure to what extent this would be exploited (which would depend on the OS implementation).
Of course, that doesn't on the surface make using a copy more efficient than using a blank slate -- except "the blank slate" is not literally nothing, and must involve allocation. The system could have a generic blank/new process template that it copies the same way,1 but that would then not really save anything vs. the copy-on-write fork. So #1 just demonstrates that using a "new" empty process would not be more efficient.
Point #2 does explain why using the fork is likely more efficient. A child's environment is inherited from its parent, even if it is a completely different executable. For example, if the parent process is a shell, and the child a web browser,
$HOME is still the same for both of them, but since either could subsequently change it, these must be two separate copies. The one in the child is produced by the original
1. A strategy that may not make much literal sense, but my point is that creating a process involves more than copying it's image into memory from disk.