Debug your shell scripts with bashdb

Source: Internet
Author: User

The
Bash debugger Project (bashdb) lets you set breakpoints, inspect variables, perform a backtrace, and step through a bash script line by line. in other words, it provides the features you have CT in a C/C ++ debugger to anyone programming a bash script.

To see if your standard bash executable has bashdb support, execute the command shown below; if you are not taken to a bashdb prompt then you'll have to install bashdb yourself.

$ bash --debugger -c "set|grep -i dbg"...bashdb<0> 

The Ubuntu intrepid repository contains
Package for bashdb, but there is no special bashdb package in the opensuse 11 or fedora 9 repositories. I built from source using version 4.0-0.1 of bashdb on a 64-bit fedora 9 machine, using the normal./configure; make; sudo make installCommands.

You can start the Bash debugger usingbash --debugger foo.shSyntax orbashdb foo.shCommand. The former method is

Recommended into T in cases where I/O redirection might cause issues, and it's what I used. You can also use bashdb throughddd or from

Emacs buffer.

The syntax for syntax of the commands in bashdb mimics that of GDB, the GNU Debugger. You canstepInto functions, use
nextTo execute the next line without stepping into any functions, generate a backtracebt, Exit bashdb
quitOr Ctrl-D, and examine a variableprint $foo. Aside from the prefixing of the variable
$At the end of the last sentence, there are some other minor differences that you'll notice. for instance, pressing enter on a blank line in bashdb executes the previous step or next command instead of whatever the previous command was.

The print Command forces you to prefix shell variables with the dollar sign ($foo). A slightly shorter way of inspecting variables and functions is to usex
foo
Command, which usesdeclareTo print variables and functions.

Both bashdb and your script run inside the same bash shell. because bash lacks some namespace properties, bashdb will include some functions and symbols into the global namespace which your script can get. bashdb prefixes its symbols_Dbg_,
So you shoshould avoid that prefix in your scripts to avoid potential clashes. bashdb also uses some environment variables; it usesDBG_Prefix for its own, and relies on some standard bash ones that beginBASH_.

To restrict strate the use of bashdb, I'll work on the small bash script below, which expects a numeric argumentnAnd calculates the nth

Fibonacci number.

#!/bin/bashversion="0.01";fibonacci() {    n=${1:?If you want the nth fibonacci number, you must supply n as the first parameter.}    if [ $n -le 1 ]; then echo $n    elsel=`fibonacci $((n-1))`r=`fibonacci $((n-2))`echo $((l + r))    fi}for i in `seq 1 10`do  result=$(fibonacci $i)  echo "i=$i result=$result"done

The below session shows bashdb in action, stepping over and then into the Fibonacci function and inspecting variables. I 've made my input text bold for processing of reading. An initial backtrace (bt) Shows that the script begins at line 3, which
Is where the version variable is written.nextAndlistCommands then progress to the next line of the script a few times and show the context of the current execution line. After one ofnextCommands I press ENTER
To executenextAgain. I invokeexamineCommand through the single letter shortcut
x. Notice that the variables are printed out usingdeclareAs opposed to their display on the next line using
print. Finally I set a breakpoint at the start offibonacciFunction and
continueThe execution of the shell script.fibonacciFunction is called and I move to
nextLine a few times and inspect a variable.

$ bash --debugger ./fibonacci.sh ... (/home/ben/testing/bashdb/fibonacci.sh:3): 3: version="0.01"; bashdb<0> bt ->0 in file `./fibonacci.sh' at line 3 ##1 main() called from file `./fibonacci.sh' at line 0 bashdb<1> next (/home/ben/testing/bashdb/fibonacci.sh:16): 16: for i in `seq 1 10` bashdb<2> list 16:==>for i in `seq 1 10` 17: do 18: result=$(fibonacci $i) 19: echo "i=$i result=$result" 20: done bashdb<3> next (/home/ben/testing/bashdb/fibonacci.sh:18): 18: result=$(fibonacci $i) bashdb<4> (/home/ben/testing/bashdb/fibonacci.sh:19): 19: echo "i=$i result=$result" bashdb<5> x i result declare -- i="1" declare -- result="" bashdb<7> print $i $result 1 bashdb<10> break fibonacci Breakpoint 1 set in file /home/ben/testing/bashdb/fibonacci.sh, line 5. bashdb<11> continue Breakpoint 1 hit (1 times). (/home/ben/testing/bashdb/fibonacci.sh:5): 5: fibonacci() { bashdb<(12)> next (/home/ben/testing/bashdb/fibonacci.sh:6): 6: n=${1:?If you want the nth fibonacci number, you must supply n as the first parameter.} bashdb<(13)> next (/home/ben/testing/bashdb/fibonacci.sh:7): 7: if [ $n -le 1 ]; then bashdb<(14)> x n declare -- n="2" bashdb<(15)> quit 

Notice that the number in the bashdb prompt toward the end of the above example is enclosed in parentheses. each set of parentheses indicates that you have entered a subshell. in this example this is due to being inside a shell function.

In the below example I use a watchpoint to see if and whereresultVariable changes. Notice the initialnextCommand. I found that if I didn't issue that next then my watch wowould fail to work. As you can see, after I issuec
To continue execution, execution is stopped whenever the result variable is about to change, and the new and old values are displayed.

(/home/ben/testing/bashdb/fibonacci.sh:3): 3: version="0.01"; bashdb<0> next (/home/ben/testing/bashdb/fibonacci.sh:16): 16: for i in `seq 1 10` bashdb<1> watch result 0: ($result)==0 arith: 0 bashdb<2> c Watchpoint 0: $result changed: old value: '' new value: '1' (/home/ben/testing/bashdb/fibonacci.sh:19): 19: echo "i=$i result=$result" bashdb<3> c i=1 result=1 i=2 result=1 Watchpoint 0: $result changed: old value: '1' new value: '2' (/home/ben/testing/bashdb/fibonacci.sh:19): 19: echo "i=$i result=$result"

To get around the strange initialnextRequirement I used
watche
Command in the below session, which lets you stop whenever an expression becomes true. in this case I'm not overly interested in the first few maid so I set a watch to have execution stop when the result is greater than 4. you can
Also usewatcheCommand without a condition; for example,watche resultWocould stop execution whenever the result variable changed.

$ bash --debugger ./fibonacci.sh (/home/ben/testing/bashdb/fibonacci.sh:3): 3: version="0.01"; bashdb<0> watche result > 4 0: (result > 4)==0 arith: 1 bashdb<1> continue i=1 result=1 i=2 result=1 i=3 result=2 i=4 result=3 Watchpoint 0: result > 4 changed: old value: '0' new value: '1' (/home/ben/testing/bashdb/fibonacci.sh:19): 19: echo "i=$i result=$result"

When a shell script goes wrong, Please folks use the time-tested method of Incrementally adding inechoOr
printfStatements to look for invalid values or code paths that are never reached. With bashdb, you can save yourself time by just adding a few watches on variables or setting a few breakpoints.

Ben Martin has been working on filesystems for more than 10 years. He completed his Ph. D. and now offers consulting services focused on libferris, filesystems, and search solutions.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.