|
From: R. B. <ro...@pa...> - 2006-12-26 18:08:17
|
Since bashdb-3.1-0.06 the bash debugger has had the ability to do line
tracing sort of like set -x, but adding a little more information,
namely position information and BASH_LEVEL information.
Recently I added string expansion of before printing lines. This is
controlled by the debugger command "set linetrace expand", and from
the bashdb script using option -Y (or long-option --vtrace if you have
a working getopt).
Here's a small example using a recursive factorial program. (Sure
there's a simpler, non-recursive way to write this - I just wanted a
small example.)
Here's the program
#!/bin/bash
fact() {
local -i n=$1
((n==0)) && echo 1 && return
((nm1=n-1))
((result=n*`fact $nm1`))
echo $result
}
typeset -i n=${1:-4}
echo fact $n is: `fact $n`
Running with line tracing and variable substitution, you get:
bashdb -B -Y fact.sh 2
Bourne-Again Shell Debugger, release bash-3.1-0.08cvs
Copyright 2002, 2003, 2004, 2006 Rocky Bernstein
This is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
(bashdb:277):
level 1, subshell 0, depth -1: . $_source_file
. fact.sh
(fact.sh:11):
level 1, subshell 0, depth 0: typeset -i n=${1:-4}
typeset -i n=2
(fact.sh:12):
level 1, subshell 0, depth 0: echo fact $n is: `fact $n`
echo fact 2 is: 2
(fact.sh:12):
level 1, subshell 1, depth 0: echo fact $n is: `fact $n`
echo fact 2 is: 2
fact $n
(fact.sh:3):
level 1, subshell 1, depth 1: fact() {
fact() {
(fact.sh:4):
level 1, subshell 1, depth 1: local -i n=$1
local -i n=2
(fact.sh:5):
level 1, subshell 1, depth 1: ((n==0)) && echo 1 && return
((n==0)) && echo 1 && return
(fact.sh:6):
level 1, subshell 1, depth 1: ((nm1=n-1))
((nm1=n-1))
(fact.sh:7):
level 1, subshell 1, depth 1: ((result=n*`fact $nm1`))
((result=n*1))
(fact.sh:7):
level 1, subshell 2, depth 1: ((result=n*`fact $nm1`))
((result=n*1))
fact $nm1
(fact.sh:3):
level 1, subshell 2, depth 2: fact() {
fact() {
(fact.sh:4):
level 1, subshell 2, depth 2: local -i n=$1
local -i n=1
(fact.sh:5):
level 1, subshell 2, depth 2: ((n==0)) && echo 1 && return
((n==0)) && echo 1 && return
(fact.sh:6):
level 1, subshell 2, depth 2: ((nm1=n-1))
((nm1=n-1))
(fact.sh:7):
level 1, subshell 2, depth 2: ((result=n*`fact $nm1`))
((result=n*1))
(fact.sh:7):
level 1, subshell 3, depth 2: ((result=n*`fact $nm1`))
((result=n*1))
fact $nm1
(fact.sh:3):
level 1, subshell 3, depth 3: fact() {
fact() {
(fact.sh:4):
level 1, subshell 3, depth 3: local -i n=$1
local -i n=0
(fact.sh:5):
level 1, subshell 3, depth 3: ((n==0)) && echo 1 && return
((n==0)) && echo 1 && return
(fact.sh:5):
level 1, subshell 3, depth 3: ((n==0)) && echo 1 && return
((n==0)) && echo 1 && return
echo 1
(fact.sh:5):
level 1, subshell 3, depth 3: ((n==0)) && echo 1 && return
((n==0)) && echo 1 && return
return
(fact.sh:8):
level 1, subshell 2, depth 2: echo $result
echo 1
(fact.sh:8):
level 1, subshell 1, depth 1: echo $result
echo 2
fact 2 is: 2
(bashdb:290):
level 1, subshell 0, depth -1:
Using -V (long option --trace), omits the substitution line getting
printed out. That is this would start out instead:
(bashdb:277):
level 1, subshell 0, depth -1: . $_source_file
(fact.sh:11):
level 1, subshell 0, depth 0: typeset -i n=${1:-4}
(fact.sh:12):
level 1, subshell 0, depth 0: echo fact $n is: `fact $n`
That very first line (bashdb:277) I'm not happy about but I don't know
how to remove it for now - and it *does* reflect what's really going
on.
Another thing to note is that the program really doesn't have deep
knowledge about what is a variable and what isn't. It is just asks
bash to expanding the source line as a string and prints the result
So in a statement like
((nm1-n-1))
nothing gets substituted.
Similarly it's possible to have a source line like
echo "Now is \
the time"
And what will happen here is invariable the debugger will see an
open/close quote (or a back tick) without the matching one. What
happens here is that the string substitute fails and nothing gets
printed.
Still, even with these caveats, I've found this addition useful.
Things are not cast in concrete right now, so if folks want to try it
out and give feedback, now would be a good time.
Thanks.
|