Debugging Shell Scripts
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 latethe 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:
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
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:
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
Reads all commands, but does not execute them.
Displays all lines as they are read.
-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:
case $- in *v*) : # verbose mode ;; *x*) : # shell tracing mode ;; esacdebugging modes
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
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):
1 #!/bin/sh 2 set -x 3 if [ -z "$1" ] ; then 4 echo "ERROR: Insufficient Args." 5 exit 1 6 fi
This script enables shell tracing (the -x option) on line 2:
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:
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.