Unix: Debugging your scripts even more effectively

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.

From CIO: 8 Free Online Courses to Grow Your Tech Skills
Join the discussion
Be the first to comment on this article. Our Commenting Policies