Debugging Bash
Verbose/Tracing
The shell lets you know what it is executing as it progresses through your script -- although it can be a little cryptic at first glance. Both features are enabled and disabled using set: set -X to enable X and set +X to disable X.
Verbose
set -v turns the verbose mode on where the shell will echo each command line before it executes it. The command is echoed as it read from the script:
% set -v % a=0 a=0 % echo $a echo $a 0 % set +v set +v
Notice here that the command echoed to the screen is the command from the script without any Expansion having been applied.
Tracing
set -x turns on tracing mode (more technically xtrace) where the shell will echo each command line before it executes it but after Expansion has been applied. In addition a prefix is printed, here it will be "+ ":
% set -x % a=0 + a=0 % echo $a + echo 0 0 % set +x + set +x
Prefix
The prefix is derived from the value of PS4 which defaults to "+ " (plus space). The first character of PS4 is repeated for each level of indirection followed by the expansion of the rest of PS4.
You might ask what constitutes a level of indirection. Good question. There's no ready definition but Process Substitution is one:
% echo The value is $(echo $a) ++ echo 0 + echo The value is 0 The value is 0
PS4
PS4 defaults to "+ " but will have variable and Process Substitution applied to it at the time it is used.
A very simple example might be to show the line number in the script:
% PS4='+ Line ${LINENO}: ' % set -x % echo $a + Line 5: echo 0 0
Note
Don't forget to single quote the value of PS4 otherwise ${LINENO} will be expanded at the time PS4 is assigned to rather than when it is used.
Another obvious extension to that would be to include the source file:
% PS4='+ ${BASH_SOURCE}: Line ${LINENO}: ' % set -x % echo $a + : Line 7: echo 0 0
OK, not so helpful on the command line. Let's try with a file:
% cat foo #! /bin/bash PS4=$'+ ${BASH_SOURCE}: Line ${LINENO}: ' set -x a=0 echo $a % ./foo + ./foo: Line 5: a=0 + ./foo: Line 6: echo 0 0
Another useful extension might be to include the time the line was run -- very handy for correlating with system logs. date lets us specify a time format on the fly:
% PS4='+ $(date +%H:%M:%S): ${BASH_SOURCE}: Line ${LINENO}: ' % set -x % echo $a + 16:37:21: : Line 9: echo 0 0
Extending the call to date would be to display how long the script has been running for at this point in time:
% PS4='+ $(date +%H:%M:%S): +${SECONDS}s: ${BASH_SOURCE}: Line ${LINENO}: ' % set -x % echo $a + 16:37:21: +37s: : Line 9: echo 0 0
Verbose and Tracing
You can combine the two:
% PS4='+ ' % set -v % set -x set -x % a=0 a=0 + a=0 % echo $a echo $a + echo 0 0
Here you can see the verbose flag is implemented first.
BASH_COMMAND
Bash 3.0 included several variables to support the Bash debugger. One of these was BASH_COMMAND which is the command being or about to be executed (except during a trap). As it happens, the value of BASH_COMMAND is the pre-Expansion value, ie the same as given by set -v. We can dispense with set -v and include BASH_COMMAND in PS4:
% PS4='+ Line ${LINENO}: ${BASH_COMMAND} => ' % set -x % echo $a + Line 37: echo $a => echo 0 0
You might want to embed newlines using String Expansion below.
String Expansion
Don't forget you can use $' ... ' String Expansion to embed newlines:
% set -x % PS4=$'+ Line ${LINENO}\n' + PS4='+ Line ${LINENO} '
Note
The trailing single quote on a line on its own! It is the expansion of the $' ... ' construct.
% echo $a + Line 10 echo 0 0
Example
A useful value for PS4 might be:
PS4=$'+ $(date +"%Y-%m-%d %H:%M:%S"): +${SECONDS}s: ${BASH_SOURCE[0]##*/}: Line ${LINENO}\n> ${BASH_COMMAND}\n> '
giving:
% echo $a + 2011-12-03 14:39:53: +96s: : Line 52 > echo $a > echo 0 0
which shows:
- the date and time
- how long the script has been running for
- the source file (empty for the command line)
- the line number
and, on separate lines for comparison:
- the pre-expansion command line
- the expanded command line
Caveat
There is an undocumented 99 character limit on the expansion of PS4 which includes however many levels of indirection are printed.
Document Actions