BASH Programming

Uses of the Exec Command in Shell Scripts

This guide elaborates on the exec command and its usage in shell scripts.

Prerequisites:

To perform the steps that are demonstrated in this guide, you need the following components:

The Exec Command

The exec command isn’t a separate tool by itself:

$ which exec

Rather, it’s an internal command of the Bash shell:

$ man exec

As the description from the man page suggests, if a command is specified, exec replaces the shell with it, spawning no additional process. There are a handful of options available that modify the behavior of the exec command.

Basic Usage

By default, whenever running a command, Bash spawns a subshell and forks the command.

$ echo $$ && sleep 999

$ pstree -p

Here, the echo command prints the PID of the current shell. The Bash shell (PID: 978) spawns a new child process to work with the sleep command (PID: 8369).

Now, what if we run the sleep command using exec?

$ echo $$ && exec sleep 999

$ pstree -p

The parent Bash process is replaced by the sleep command. Upon successful execution, it does not return to the shell. Instead, the session is terminated.

Clean Environment

The default Bash configuration comes with a bunch of tweaks and environment variables. In certain scenario (debugging, for example), you may want to run your script/program in a clean environment. With the help of exec, we can launch a clean shell instance in place of the current one.

First, use the printenv command to list all the environment variables that are currently configured:

$ printenv

Now, use exec to launch a clean instance:

$ exec -c bash

$ printenv

Launching a Different Shell

Besides Bash and “sh”, there are multiple other shell programs available, each with their unique perks. If a program/script requires a specific shell, you can use exec to replace the current Bash shell with the desired one.

In the following example, we replace Bash with “sh”:

$ pstree -p

$ exec sh

$ pstree -p

Using Exec in Scripts

With the basics out of the way, we can now start using exec in our shell scripts.

Example 1: Working with Different Shells

Check out the following script:

#!/bin/bash

echo $SHELL

echo "echo zsh launched successfully" > zsh.sh

exec zsh zsh.sh

Here, the first echo command prints the current shell. By default, it should be Bash. Then, the exec command launches “zsh” to execute the “zsh.sh” script.

Run the following script:

$ ./test.sh

Example 2: Overriding the Existing Process

Whenever calling a command/program, Bash spawns a new process. In most situations, it’s not a matter of concern. However, when working with a system with very limited resource (embedded hardware, for example), using exec to override the existing process in memory can help.

Check out the following script:

#!/bin/bash

pstree -p

exec pstree -p

echo "hello world"

Here, the first pstree command shows the original layout of the process tree. Once the exec command is executed, the second pstree command replaces the running shell. The echo command on the last line didn’t execute.

Run the following script:

$ ./test.sh

Since it was a part of the script, we return to the original shell upon successful execution.

As the exec command replaces the parent shell with a different command/program, any code after that becomes invalid. Be careful when using them in your scripts.

Example 3: Logging

The Bash shell offers 3 unique file descriptors to any running program/script:

  • STDOUT (1): standard output, stores normal output
  • STDERR (2): standard error, stores error messages
  • STDIN (0): standard input

Using exec, we can redirect these file descriptors to a different location, for example: log files. It can help with debugging and logging in general.

Generally, if you want to redirect STDOUT and STDERR to a log file, you use the redirect operator:

$ echo $$ | tee test.log

$ monke 2>&1 | tee test.log

This method requires redirection at every point that you want to log. To solve this issue, we can use the exec command to create a permanent redirect for the shell session. Check out the following example:

#!/bin/bash

> test.log

exec 1>>test.log

exec 2>&1

echo "hello world"

wrong_command

Here, the first line creates an empty log file. The first exec command establishes a permanent redirect of STDOUT to the log file. The second exec command redirects STDERR to STDOUT.

With this setup, all the outputs and error messages are dumped into the log file:

$ ./test.sh

$ cat test.log

What if the script generates continuous log entries?

#!/bin/bash

> test.log

exec 1>>test.log

exec 2>&1

while true

do

echo $RANDOM

sleep 5

done

Here, in the first portion, we create a permanent redirect of STDOUT and STDERR to our log file. The infinite while loop runs the echo command until we close it forcibly using “Ctrl + C”. The $RANDOM variable is a special variable that returns a random string every time it’s accessed.

To check the updating log entry, use the following tail command:

$ tail -f test.log

Note that this redirection only lasts for the shell session.

Example 4: Input from File

Similar to how we created a permanent STDOUT and STDERR redirect, we can also create one for STDIN. However, since STDIN is used for input, the implementation is a bit different.

In the following script, we take STDIN from a file:

#!/bin/bash

echo "echo "hello world"" > input

exec < input

read line_1

eval $line_1

Here, in the first line, we use echo to generate the content of input_string file using redirection. The exec command redirects the content of input_string to STDIN of the current shell session. After reading the string, we use eval to treat the content of $line_1 as a shell code.

Run the following script:

$ ./test.sh

Conclusion

We discussed about the exec command in Bash. We also showcased the various ways of using it in scripts. We demonstrated using exec to work with multiple shells, create memory efficient scripts, and redirect the file descriptors.

This is just a small portion of what can be achieved using the Bash scripting. Learn more about Bash scripting from the Bash programming sub-category.

Happy computing!

About the author

Sidratul Muntaha

Student of CSE. I love Linux and playing with tech and gadgets. I use both Ubuntu and Linux Mint.