Tracing Variables in Shell Scripts

Sometimes you need a little more detail when debugging a bash script than bash -x alone will give you. The following modifies PS4 to contain the line number of each line of output.

#!/bin/bash -x
me=`basename $0`
export 'PS4=+ $me.$LINENO '
function testfunction() {
  echo $*
}
testfunction testing
testfunction 123

For example

$ ./test.sh
++ basename ./test.sh
+ me=test.sh
+ export 'PS4=+$me.$LINENO '
+ PS4='+$me.$LINENO '
+ test.sh.7 testfunction testing
+ test.sh.5 echo testing
testing
+ test.sh.8 testfunction 123
+ test.sh.5 echo 123
123
$

If you’re having trouble with a particular variable and cannot figure out where it’s going wrong, combining the above line numbering with the following DEBUG trap may help:

#!/bin/bash -x
me=`basename $0`
export 'PS4=+$me.$LINENO '
trap 'echo "VARIABLE-TRACE> \$somevariable= \"${somevariable}\""' DEBUG
function testfunction() {
  echo $*
  [[ -n ${somevariable} ]] && unset somevariable
}

somevariable=testing
testfunction ${somevariable}
testfunction ${somevariable}

And here’s the output:

$ ./test.sh
++ basename ./test.sh
+ me=test.sh
+ export 'PS4=+ $me.$LINENO '
+ PS4='+ $me.$LINENO '
+ test.sh.4 trap 'echo "VARIABLE-TRACE> \$somevariable= \"${somevariable}\""' DEBUG
++ test.sh.10 echo 'VARIABLE-TRACE> $somevariable= ""'
VARIABLE-TRACE> $somevariable= ""
+ test.sh.10 somevariable=testing
++ test.sh.11 echo 'VARIABLE-TRACE> $somevariable= "testing"'
VARIABLE-TRACE> $somevariable= "testing"
+ test.sh.11 testfunction testing
+ test.sh.6 echo testing
testing
+ test.sh.7 [[ -n testing ]]
+ test.sh.7 unset somevariable
++ test.sh.12 echo 'VARIABLE-TRACE> $somevariable= ""'
VARIABLE-TRACE> $somevariable= ""
+ test.sh.12 testfunction
+ test.sh.6 echo

+ test.sh.7 [[ -n '' ]]
$