Skip to content. | Skip to navigation

Navigation

You are here: Home / Support / Guides / Scripting / Bash / Debugging Bash / Verbose/Tracing

Personal tools

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