Relentless Coding

A Developer’s Blog

Bash's exec Replaces Shell

This is a quick look at Bash’s exec builtin with a simple example.

bash(1) explains exec [command]:

If command is specified, it replaces the shell. No new process is created.

This is mainly useful for wrapper scripts, where we do not want to have a Bash process lingering around. Take this script named test:

#!/bin/bash

sleep inf

When run as ./test, the current shell creates a new Bash instance (the interpreter specified in the first line of the script with the shebang #!/bin/bash), and then creates a new process for the sleep command. So, we have 2 processes running: a Bash and a sleep process:

$ ps -o pid,ppid,cmd -T
    PID    PPID CMD
   2443     969 -bash
   5348    2443 /bin/bash ./test
   5349    5348 sleep inf
   5358    2443 ps -o pid,ppid,cmd -T

When we background ./test with Ctrl-Z and use ps(1) with the -T flag, it prints the processes associated with the current terminal session. PID 2443 is the current terminal. We see that 2443 spawned /bin/bash ./test (PID 5348) which in its turn begat sleep inf (PID 5349).

Now we modify the script to use exec to execute sleep:

#!/bin/bash

exec sleep inf

Again, the current shell executes a new Bash process. But instead of it creating a new sleep process, the sleep process replaces it. Now we only have single process (sleep) running:

$ ps -o pid,ppid,cmd -T
    PID    PPID CMD
   2443     969 -bash
   5399    2443 sleep inf
   5407    2443 ps -o pid,ppid,cmd -T

Here, we see that sleep inf has as its parent the shell that invoked ./test: it has replaced /bin/bash ./test.