Last week's post provided some tips and tricks for debugging scripts. This week's provides some even better ones!
In last week’s posting, I mentioned the -x and -v options that can be used on the shebang line to turn on trace or verbose options so that, when you run your script, you see each command as it is being executed. Well, this isn’t the only way that you can use these options. You can also turn them on and off at various points within your scripts. If you only want to see what’s happening within one particular section or several sections of your script, surround that section or those sections of your script with set -x and set +x commands. These turn debugging on anf off just for those sections of code.
set -x # turn debugging on
while [ $x -le $end ]; do
number=$x
if [ $padlen -gt 1 ]; then
while [ ${#number} -lt $padlen ]; do number="0${number}"; done
fi
echo -n "$number"
[ $x -lt $end ] && echo -n " "
x=$(( $x + 1 ))
done
set +x
Taking this even a little further, you can set a debug variable (e.g., DEBUG=”set -x”) outside of your script and then insert $DEBUG at various place in your script. To do this, you would use a variable in your script. For example:
$DEBUG while [ $x -le $end ]; do ...
When DEBUG isn’t defined, this variable has no effect whatsoever. It’s basically a blank line. When you set it outside of your script, on the other hand, it turns into a set -x command.
$ export DEBUG='set -x' $ ./myscript ...
If you want to turn debugging on and off, you can set up two variables, maybe DEBUGON and DEBUGOFF, and use then both.
#!/bin/bash echo Greeting, $USER $DEBUGON echo "what do you see?" $DEBUGOFF echo "That's enough for now"
Then
$ export DEBUGON='set -x' $ export DEBUGOFF='set +x'
The benefit of this approach is that you don’t have to edit any commands out of your script when you are ready to go production. The use of DEBUG, DEBUGON and DEBUGOFF have no effect unless you set the variables.
Another good thing to know is that you don’t have to put a -x or -v on your shebang lines to use these features. So, you don’t have to actually modify a script to do command tracing. Instead, you can do this:
$ bash -x myscript
You can also expand on the information that the -x option will provide by modifying your PS4 setting. PS4 defines the prompt that is displayed when you’re using debug mode. If you set your PS4 variable like this, you will see your script name, line number and, if applicable, your function name when you are debugging your script.
$ export 'PS4=+${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]}: '
Here’s a sample script:
#!/bin/bash
function quit {
exit
}
function greet {
echo Hello, $USER!
}
greet
quit
Here we run the script in debug mode:
$ bash -x foo +:96:: bash -x foo +foo:9:: greet +foo:7:greet: echo Hello, 'shs!' Hello, shs! +foo:10:: quit +foo:4:quit: exit
PS4 settings provide a lot more context for your debugging efforts. And you can make the output even more interesting if you like. My Internet rambling friend, Sandwich Maker, suggests these settings to put your script name in bold and underline your line numbers:
export BOLD=$(tput bold) SMUL=$(tput smul) SGR0=$(tput sgr0)
PS4="${BOLD}${0##*/}${SGR0} line ${SMUL}${LINENO}${SGR0}:t"
Thanks to Sandwich Maker (Andrew Hay), Len Weisberg and JuzJoe for sharing their insights on debugging.




