7

From this link I get the following about exec bash builtin command:

If command is supplied, it replaces the shell without creating a new process.

How does it exactly replace the shell (i.e. how does it work internally)? Does the exec*() system call work the same?

syntagma
  • 12,311

2 Answers2

8

Yes, the exec builtin ultimately makes use of one of the exec*() family of system calls. So does running commands normally. It's just that when you use exec, it doesn't use the fork() system call first to create a new process, and the result is that the new command replaces the shell.

Celada
  • 44,132
7

I did a strace on a running bash instance. Then I invoked the command exec sleep 100. Now see what happend:

access("/bin/sleep", X_OK)              = 0
...
execve("/bin/sleep", ["sleep", "100"], [/* 14 vars */]) = 0
...
nanosleep({100, 0},
...
exit_group(0)                           = ?

So you can see, it happend nearly the same as when you call sleep the normal way. bash checks if executable permission (X_OK) is granted for /bin/sleep with the access() system call. Then execve() executes the program pointed to by filename. After execve() syscall, sleep has the control over the process. Does it's things: nanosleep(). It also kepps the same pid. After sleep ended the process ends too. Whether sleep nor bash is not running anymore.

Evidence:

In another window I watched the process with ps. Before running the command it looked like this:

$ ps -o stat,pid,cmd -p <pid>
Ss+  10905 -bash

And while running:

$ ps -o stat,pid,cmd -p <pid>
Ss+  10905 sleep 100

Afer sleep ended the process disapeared.

What happend when I run it normally?

access("/bin/sleep", X_OK)              = 0
...
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f6c9fd089d0) = 19261
...
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 19261
...
--- SIGCHLD (Child exited) @ 0 (0) ---

The execution permission is checked. Then a child process is created clone(). The bash instance is now in the background process group, sleep is in the foreground process group. And at last, the wait4() call waits until the child process ended (that needs 100 seconds).

chaos
  • 48,171