Debugging Shell Scripts

Sometimes the hardest part about shell programming is finding the bugs in your scripts. This lesson walks you through the various features of the shell along with some other techniques to help you track down and fix the bugs in your scripts.

This chapter is from the book

Most of the scripts you have looked at have been quite short, thus the issue
of debugging has boiled down to examining the output to ensure it is correct.
For larger shell scripts, especially scripts used to change system configurations,
trying to deduce the source of a problem based on just output is insufficient.
By the time you get the output it might be too latethe script could have
made incorrect and possibly destructive modifications.

Fortunately, the shell provides several built-in commands for enabling different
modes of debugging support. The built-in debugging support can be very helpful
when you need to add features to a large script that someone else developed;
it can help you ensure that your changes don't affect the rest of the script.

This chapter covers several techniques for debugging shell scripts, with a
concentration on the following:

Syntax checking

Shell tracing

Enabling Debugging

By now, you are quite familiar with the basic syntax for executing a shell
script:

$ script arg1 arg2 ... argN

Here script is the name of the script and arg1 through argN are the arguments
to the script.

An alternative method to execute a shell script is

$ /bin/sh opt script arg1 arg2 ... argN

This invokes the shell, in this case /bin/sh, with the debugging
option specified by opt and instructs the shell to execute script. Table 20.1
lists the various debugging options.

A second way to enable debugging is to change the first line of script.
Usually, the first line of a script is

#!/bin/sh

UNIX uses this line to determine the shell you can use to execute a script.
This indicates that the shell /bin/sh should be used to execute the
script. You can modify this line, as follows, in order to specify a debugging
option:

#!/bin/sh opt

These methods for enabling debugging modes take effect when a script is
invoked, so they are sometimes referred to as invocation activated
debugging modes.

Table 20.1 Debugging Options for Shell Scripts

Name

Option

Description

No Exec

-n

Reads all commands, but does not execute them.

Verbose

-v

Displays all lines as they are read.

Execution Trace

-x

-Displays commands and their arguments as they are executed. Often referred
to as shell tracing.

Debugging and $-

When one of the debugging options is activated, a letter corresponding to
that option is added to the variable $-. For example, if the
-v (verbose) option is used, the letter v is added to
$-. Similarly when the -x is used, the letter x is added to
$-.

You can detect if one of these options is active by using a case statement
similar to the following:

Using the set command

In the invocation activated debugging modes, the debugging mode takes effect
at the start of the script and remains in effect until the script exits. Most of
the time you need to debug just one function or a small section of your script.
In these cases, enabling debugging for the entire script is overkill.

As you will see later in this chapter, the debugging output is quite
extensive, and it is often hard to sort out the real errors from the noise. You
can address this problem by using the set command to enable the
debugging modes just in the parts of the script where you need debugging
information.

Enabling Debugging Using set

The basic syntax of the set command is

set opt

Here opt is one of the options listed in Table 20.1.

The set command can be used anywhere in a shell script, and many
scripts use it to change the debugging flags as part of the normal execution of
the script. Because these debugging modes are activated only when the shell
script programmer uses the set command, they are sometimes referred to
as programmer activated modes.

Consider the following excerpt from a shell script (the line numbers are
provided for your reference):

Because this command occurs before the if statement (lines 3 through
6), shell tracing will be active while the if statement executes.
Unless explicitly disabled later in the script, shell tracing will remain in
effect until the script exits. You will look at the effect of shell tracing on
the output of a script in the "Shell Tracing" section of this
chapter.

Disabling Debugging Using set

You can use the set command to disable a debugging mode as
follows:

set +opt

Here opt is a letter corresponding to one of the options given in Table 20.1.
For example, the following command disables shell tracing:

$ set +x

To deactivate any and all the debugging modes that have been enabled, you can
use the command:

$ set -

Enabling Debugging for a Single Function

One of the most common uses of the set command is to enable a
particular debugging mode before a function executes and then disable debugging
when the function finishes.

For example, say you have a problematic function named
BuggyFunction() and you want to enable shell tracing only while that
function executes. You could use the following command:

set -x ; BuggyFunction; set +x ;

Here the debugging mode is enabled just before the function is called and is
disabled after the function completes. This method is favored over explicitly
using the set command inside a function to enable debugging because it
enables the implementation of the function to remain unchanged.