📄 bashdb.texi
字号:
command number, starting with 3, or the third command entered, nowappears in parenthesis. Each subshell nesting adds a set ofparenthesis.The first @kbd{step} command steps the script one instruction; itdidn't advance the line number, 9, at all. That is because we werestopping before the command substitution or backtick is to takeplace. The second command we entered was just hitting the return key;bashdb remembers that you entered @code{step} previously, so it runsthe step rather than @kbd{next}, the other alternative when you hit@key{RET}. Step one more instruction and we are just before runningthe first statement of the function.Next, we print the value of the variable @kbd{n}. Notice we need to adda preceding dollar simple to get the substitution or value of n. As wewill see later, if the @kbd{pe} command were used this would not benecessary. We now modify the file to add an assignment to local variable @kbd{n} andrestart.@smallexample@cartouchebashdb<6> @b{restart}Restarting with: /usr/local/bin/bashdb -L . fact.sh(/tmp/fact.sh:10):10: echo fact 0 is: `fact 0`bashdb<0> @b{list 1} 1: #!/usr/local/bin/bash 2: fact() @{ 3: local -i n=$@{1:0@} 4: ((n==0)) && echo 1 && return 5: ((nm1=n-1)) 6: ((result=n*`fact $nm1`)) 7: echo $result 8: @} 9: 10:==> echo fact 0 is: `fact 0`bashdb<1> @b{s 3}(/tmp/fact.sh:3):3: local -i n=$@{1:0@}bashdb<(2)> @b{step}(/tmp/fact.sh:4):4: ((n==0)) && echo 1 && returnbashdb<(3)> @b{print $n}print $n0@end cartouche@end smallexample @noindentThis time we use the @code{list} debugger command to list the lines inthe file. From before we know it takes three @code{step} commandsbefore we get into the fact() function, so we add a count onto the@code{step} command. Notice we abbreviate @code{step} with @code{s};we could have done likewise and abbreviated @code{list} with @code{l}.@smallexample@cartouchebashdb<(4)> @b{@key{RET}}(/tmp/fact.sh:4):4: ((n==0)) && echo 1 && returnecho 1bashdb<(5)> @b{@key{RET}}(/tmp/fact.sh:4): 4: ((n==0)) && echo 1 && returnreturn@end cartouche@end smallexample @noindentAgain we just use @key{RET} to repeat the last @code{step}commands. And again the fact that we are staying on the same line 4means that the next condition in the line is about to beexecuted. Notice that we see the command (@code{echo 1} or@code{return}) listed when we stay on the same line which has multiplestopping points in it. Given the information above, we know that thevalue echo'ed on return will be 1.@smallexample@cartouchebashdb<(6)> @b{@key{RET}}fact 0 is: 1(/tmp/fact.sh:12): 12: echo fact 3 is: $(fact 3)bashdb<(7)> @b{break 5}Breakpoint 1 set in file fact.sh, line 5.bashdb<(8)> @b{continue}@end cartouche@end smallexample @noindentWe saw that we could step with a count into the functionfact(). However above took another approach: we set a stopping point or``breakpoint'' at line 5 to get us a little ways into the fact()subroutine. Just before line 5 is to executed, we will get back intothe debugger. The @code{continue} command just resumes execution untilthe next stopping point which has been set up in some way.@smallexample@cartouche(/tmp/fact.sh:5):5: ((nm1=n-1))Breakpoint 1 hit(1 times).bashdb<(8)> @b{x n-1}2bashdb<(9)> @b{s}(/tmp/fact.sh:5):6: ((result=n*`fact $nm1`))bashdb<(10)> @b{c}fact.sh: line 6: ((: result=n*: syntax error: operand expected (error token is "*")bashdb<(7)> @b{R}Restarting with: bash --debugger fact.sh 11: echo fact 0 is: `fact 0`bashdb<0> @b{l fact} 2: fact () 3: @{ 4: local -i n=$@{1:0@}; 5: (( "n==0" )) && echo 1 && return; 6: (( nm1=n-1 )); 7: ((fact_nm1=`fact $nm1`)) 8: (( "result=n*fact_nm1" )); 9: echo $result10: @}@end cartouche@end smallexample@noindentIn addition to listing by line numbers, we can also list giving afunction name. Below, instead of setting a breakpoint at line 5 andrunning ``@code{continue}'' as we did above, we try something slightlyshorter and slightly different. We give the line number on the``continue'' statement. This is a little different in that a one-timebreak is made on line 5. Once that statement is reached the breakpointis removed.@smallexample@cartouchebashdb<1> @b{continue 5}One-time breakpoint 1 set in file fact.sh, line 5.fact 0 is: 1(/tmp/fact.sh:5):5: ((nm1=n-1))bashdb<(2)> @b{s}6: ((fact_nm1=`fact $nm1`))bashdb<(3)> @b{s}2: fact() @{bashdb<(4)> @b{T}->0 in file `fact.sh' at line 2##1 fact("3") called from file `fact.sh' at line 12##2 source("fact.sh") called from file `/usr/local/bin/bashdb' at line 154##3 main("fact.sh") called from file `/usr/local/bin/bashdb' at line 0bashdb<(5)> @b{c}fact 3 is: 6Debugged program terminated normally. Use q to quit or R to restart.@end cartouche@end smallexample@noindentWhen we stop at line 5 above, we have already run fact(0) and outputthe correct results. The output from the program ``fact 0 is: 1'' isintermixed with the debugger output. The @code{T} command aboverequests call stack output and this confirms that we are not in thefact(0) call but in the fact(3) call. There are 4 lines listed in thestack trace even though there is just one call from the mainprogram. The top line of the trace doesn't really represent a call,it's just where we currently are in the program. That last line is anartifact of invoking bash from the bashdb script rather than running@code{bash --debugger}.The last message in the output above @samp{Debugged program exitednormally.} is from @value{DBG}; it indicates script has finishedexecuting. We can end our bashdb session with the bashdb@code{quit} command.Above we did our debugging session on the command line. If you are aGNU Emacs user, you can do your debugging inside that. Also there isa(nother) GUI interface called DDD that supports @value{DBG}.@node Interactive Line Tracing Session@section Interactive Line Tracing SessionOne of the things I had found annoying about ``@code{set -x}'' tracing isthat no position information given in the trace output, in particularthe line number and the file name. However I learn in@url{http://raz.cx/blog/2005/08/handy-bash-debugging-trick.html} thatone can set @code{$PS4} to rectify this.Here's what I use:@example@cartouche export PS4='($@{BASH_SOURCE@}:$@{LINENO@}): $@{FUNCNAME[0]@}\n'@end cartouche@end exampleThis can be set in one's @code{.bashrc}, or added as a line in yourscript before ``@code{set -x}''.There is also facility inside the bash debugger showing positioninformation when tracing a script. Here's a simple session.@example@cartouche@b{/usr/local/bin/bashdb /tmp/fact.sh}Bourne-Again Shell Debugger, release bash-@value{VERSION}Copyright 2002, 2003, 2004, 2006, 2007 Rocky BernsteinThis is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.(/tmp/fact.sh:11):11: echo fact 0 is: `fact 0`bashdb<0> @b{set linetrace on}bashdb<1> @b{cont}(/tmp/fact.sh:11):level 1, subshell 1, depth 0: echo fact 0 is: `fact 0`fact 0(/tmp/fact.sh:2):level 1, subshell 1, depth 1: fact() @{(/tmp/fact.sh:3):level 1, subshell 1, depth 1: local -i n=$@{1:0@}(/tmp/fact.sh:4):level 1, subshell 1, depth 1: ((n==0)) && echo 1 && return(/tmp/fact.sh:4):level 1, subshell 1, depth 1: ((n==0)) && echo 1 && returnecho 1(/tmp/fact.sh:4):level 1, subshell 1, depth 1: ((n==0)) && echo 1 && returnreturnfact 0 is: 1(/tmp/fact.sh:13):level 1, subshell 0, depth 0: echo fact 3 is: $(fact 3)(/tmp/fact.sh:13):level 1, subshell 1, depth 0: echo fact 3 is: $(fact 3)fact 3(/tmp/fact.sh:2):level 1, subshell 1, depth 1: fact() @{(/tmp/fact.sh:3):level 1, subshell 1, depth 1: local -i n=$@{1:0@}(/tmp/fact.sh:4):level 1, subshell 1, depth 1: ((n==0)) && echo 1 && return(/tmp/fact.sh:5):level 1, subshell 1, depth 1: ((nm1=n-1))(/tmp/fact.sh:6):level 1, subshell 1, depth 1: ((fact_nm1=`fact $nm1`))(/tmp/fact.sh:6):level 1, subshell 2, depth 1: ((fact_nm1=`fact $nm1`))fact $nm1(/tmp/fact.sh:2):level 1, subshell 2, depth 2: fact() @{...level 1, subshell 4, depth 4: fact() @{(/tmp/fact.sh:3):level 1, subshell 4, depth 4: local -i n=$@{1:@}(/tmp/fact.sh:4):level 1, subshell 4, depth 4: ((n==0)) && echo 1 && return(/tmp/fact.sh:4):level 1, subshell 4, depth 4: ((n==0)) && echo 1 && returnecho 1(/tmp/fact.sh:4):level 1, subshell 4, depth 4: ((n==0)) && echo 1 && returnreturn(/tmp/fact.sh:7):level 1, subshell 3, depth 3: ((result=n*fact_nm1))(/tmp/fact.sh:8):level 1, subshell 3, depth 3: echo $result(/tmp/fact.sh:7):level 1, subshell 2, depth 2: ((result=n*fact_nm1))(/tmp/fact.sh:8):level 1, subshell 2, depth 2: echo $result(/tmp/fact.sh:7):level 1, subshell 1, depth 1: ((result=n*fact_nm1))(/tmp/fact.sh:8):level 1, subshell 1, depth 1: echo $resultfact 3 is: 6(/usr/local/bin/bashdb:260):level 1, subshell 0, depth -1: Debugged program terminated normally. Use q to quit or R to restart.bashdb<2> @end cartouche@end exampleAn explanation of the output. The @emph{level} is how many invocationsof @value{BASH} are in effect before the statement shown isexecuted. The @emph{subshell} is how many subshells you are nestedin. Subshells are used by command substitution---@code{`..'} and@code{$(...)}---as well as arithmetic expressions @code{((...))}. The@emph{depth} is the function depth or how many calls you are nestedin. A ``source'' command also increases this depth.Notice also that in contrast to @code{set -x} tracing, the line shownis exactly as you entered it in the source. So if you indentedstatements in a meaningful way, it will help you understand thestatement nesting level. But as before, if a line contains multiplestatements, you are @emph{not} executing the first statement in theline and @code{set showcommand} is not turned off (by default it ison), that statement is shown in addition below the multi-statementline. Such an example can be seen right at the beginning where@code{fact 0} is shown.If what you want to do is trace the @emph{entire} script as was doneabove (and not stop in the debugger when the script is over), you canget the same effect by using the @code{-X} or @code{--trace} option onthe @code{bashdb} command:@example@cartouche@b{/usr/local/bin/bashdb -X /tmp/fact.sh}Bourne-Again Shell Debugger, release bash-@value{VERSION}Copyright 2002, 2003, 2004, 2006, 2007 Rocky BernsteinThis is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.(/usr/local/bin/bashdb:272):level 1, subshell 0, depth -1: . $_source_file(/tmp/fact.sh:11):level 1, subshell 0, depth 0: echo fact 0 is: `fact 0`(/tmp/fact.sh:11):level 1, subshell 1, depth 0: echo fact 0 is: `fact 0`fact 0(/tmp/fact.sh:2):level 1, subshell 1, depth 1: fact() @{(/tmp/fact.sh:3):level 1, subshell 1, depth 1: local -i n=$@{1:0@}...level 1, subshell 2, depth 2: echo $result(/tmp/fact.sh:7):level 1, subshell 1, depth 1: ((result=n*fact_nm1))(/tmp/fact.sh:8):level 1, subshell 1, depth 1: echo $resultfact 3 is: 6(/usr/local/bin/bashdb:285):level 1, subshell 0, depth -1: @end cartouche@end exampleIf you issue a break (e.g. send a @code{SIGINT} signal) while theprogram is running you will go into the debugger (assuming your
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -