Previous | Table of Contents | Next |
As mentioned before, there is at least one logical bug in this script. With the help of shell tracing, you can locate and fix this bug.
Consider the prompt produced by this script:
Make backup (y/n)?
If you do not type a response and press Enter, the script reports an error similar to the following:
./buggy3.sh: [: =: unary operator expected
To determine where this error occurs, it is best to run the entire script in shell tracing mode:
$ /bin/sh -x ./buggy3.sh
The output is similar to the following:
+ YesNo Make backup + echo Make backup (y/n)? \c + /bin/echo Make backup (y/n)? \c Make backup (y/n)? + read RESPONSE + [ = y ] ./buggy3.sh: [: =: unary operator expected
Here the blank line is the result of pressing Enter instead of typing a response to the prompt, as you can see from the next line that the shell executes:
[ = y ]
This is part of the if statement:
if [ $RESPONSE = "y" ] ; then
Although this can be fixed by changing the if statement
if [ "$RESPONSE" = "y" ] ; then
the correct fix for this problem is to track down the reason why the variable RESPONSE is not set. This variable is set by the function YesNo:
YesNo() { echo "$1 (y/n)? \c" read RESPONSE case $RESPONSE in [yY]|[Yy][Ee][Ss]) RESPONSE=y ;; [nN]|[Nn][Oo]) RESPONSE=n ;; esac }
There are two problems with this script. The first is that the read command
read RESPONSE
does not set a value for RESPONSE if the user presses Enter without typing some input. Because you cannot change the read command, you need to look for some other method of solving this problem.
This leads you to a logical problemthe case statement is not validating the user input. A simple fix is the following:
YesNo() { echo "$1 (y/n)? \c" read RESPONSE case "$RESPONSE" in [yY]|[Yy][Ee][Ss]) RESPONSE=y ;; *) RESPONSE=n ;; esac }
Here you treat all responses other than yes responses as negative responses, including no response at all.
In the previous examples, you were able to deduce the location of a bug by using shell tracing for either the entire script or for part of the script. In the case of enabling tracing for a part of a script, you had to edit the script to insert the debug command:
set -x
In larger scripts, a more common practice is to embed debugging hooks. Debugging hooks are functions that enable shell tracing during functions or critical code sections. They are activated in one of two ways:
Here is a function that enables you to activate and deactivate debugging at will if the variable DEBUG is set to true:
Debug() { if [ "$DEBUG" = "true" ] ; then if [ "$1" = "on" -o "$1" = "ON" ] ; then set -x else set +x fi fi }
To activate debugging, use the following:
Debug on
To deactivate debugging, use either of the following:
Debug Debug off
Actually, any argument passed to this function other than on or ON deactivates debugging.
As an example of using this function, modify the functions in the script buggy3.sh to have debugging automatically enabled if the variable DEBUG is set. The modifications are as follows:
#!/bin/sh Debug() { if [ "$DEBUG" = "true" ] ; then if [ "$1" = "on" -o "$1" = "ON" ] ; then set -x else set +x fi fi } Failed() { Debug on if [ "$1" -ne 0 ] ; then echo "Failed. Exiting." ; exit 1 ; fi echo "Done." Debug off } YesNo() { Debug on echo "$1 (y/n)? \c" read RESPONSE case "$RESPONSE" in [yY]|[Yy][Ee][Ss]) RESPONSE=y ;; *) RESPONSE=n ;; esac Debug off } YesNo "Make backup" if [ "$RESPONSE" = "y" ] ; then echo "Deleting old backups, please wait \c" rm -r backup > /dev/null 2>&1 Failed $? echo "Making new backups, please wait \c" cp -r docs backup Failed $? fi
The output will be normal if the script executes in either of the following methods:
$ /bin/sh ./buggy3.sh $ ./buggy3.sh
The output includes shell tracing if the same script executes in either of the following methods:
$ DEBUG=true /bin/sh ./buggy3.sh $ DEBUG=true ./buggy3.sh
In the process of developing or maintaining large shell scripts, you need to find and fix bugs that occur in them. In this chapter you looked at the tools provided by the shell to ease the task of debugging shell scripts. Some of the topics you covered are
By learning the techniques used in debugging shell scripts, you can fix your own scripts as well as maintain scripts written by other programmers.
Previous | Table of Contents | Next |