« Previous 1 2 3 Next »
Debugging Bash scripts automatically
Bug Hunting
Troubleshooting at the Command Line
Working in Eclipse is convenient but not always possible in practice (e.g., on a server without a graphical environment). Even though the Eclipse debugger is able to contact shell scripts running on external servers, it is not a very convenient approach. Bash Debugger is a better alternative; you can install this on your workstation by typing:
sudo apt-get install bashdb
After successfully completing the installation, you can instrument the execution of scripts by prefixing them with the bashdb
command. To launch the script created above, which resides in the Eclipse workspace, enter:
tamhan@TAMHAN14:~/workspace$ bashdb ./firsttest.sh bash debugger, bashdb, release 4.2-0.8 ...
The classic bashdb
step-by-step debugger comes with more than two dozen commands. A complete list can be found on the corresponding SourceForge page [5]. However, the command line of the program is a bit confusing; for example, look at the following extract:
: 3: a=1234567890 bashdb<2>
For each line, the debugger informs you which script you are currently in and which statements the line contains. Below this is the bashdb
prompt for the input of commands.
The value in the angle brackets, normally only a consecutive number, is bracketed multiple times if the program flow is nested deeper in stack frames.
If you want to walk through the code step by step, you can do so by entering next
several times (Figure 4). Remember that bashdb
does not terminate after program execution; you need to press q
and Enter to exit the debugger mask.
Step-by-Step with Exit Option
Developers brought up on the GNU Debugger know that step-by-step debuggers implement a comparatively complex command line, from which the user can also obtain information about the content of the currently loaded variable. The current content of a variable can be output, for example, with the examine
command if you know the variable name:
bashdb<6> examine a declare -- a="1234567890"
Bash scripts can be nested through functions and loops. The script below executes a wildcard calculation within a function:
function worker { for i in `seq 1 10`; do echo "worker says: " $i done } echo "go!" worker echo "end!"
If you run this program in bashdb
, you will notice that you only have to enter next
three times. The entire body of worker
is processed in one step. Control only returns in the echo "end!"
line.
Special features of bashdb
are the alternative step
and finish
commands. For lines like for i in `seq 1 10`;
that comprise multiple statements, the step
command tells the debugger to go one step deeper into your program.
Each line of the program is only accessed once, so for the loop, you toggle between the for
and echo
statements. If you get bored with this procedure at some point, you can tell bashdb
to leave the current execution context by typing finish bashdb
. However, this must be a file loaded into the script or a called function – at the moment, it is not possible to break out of a "classic" loop in this way.
Working with Breakpoints
Linear code execution will tend to become annoying if your shell script contains several hundred or even several thousand lines. Breakpoints let you work around this problem. Their behavior in bashdb
is pretty much what you will be used to with debuggers for other programming languages.
Developers have two options at this point: You can create the desired breakpoints after starting the bashdb
session, or you can use bashdb-trace
. In the first option, the debugger recognizes various breakpoint declarations that let you address line numbers, files, and function names. This first example sets a breakpoint in the worker
function:
9: echo "go!" bashdb<0> break worker Breakpoint 1 set in file /home/tamhan/workspace/functest.sh, line 1.
The following three statements set breakpoints variously by line number:
break 28 Breakpoint 2 set in file parm.sh, line 28. break parm.sh:29 Breakpoint 3 set in file parm.sh, line 29. break 28 if x==5 Breakpoint 4 set in file parm.sh, line 28.
The first statement sets a breakpoint in the specified line of the currently opened file. The second statement demonstrates how to address "remote" files – unfortunately, it is not possible to specify function names here. The third statement shows a conditional breakpoint, which is only activated when its condition is met. In all cases, a program with breakpoints is run by entering cont
:
bashdb<1> cont
After this command, the code runs until bashdb
detects the activation of a breakpoint. At that point, you can either take action by typing next
or start another pass by entering cont
. If you are interested in specific changes to variables, you will want to use watchpoints instead, which you can set up with watch
. The procedure is the same as for classic breakpoints.
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)