LinuxSir.Org  
| 网站首页 | 注册账号 | 论坛帮助 |

欢迎来到LinuxSir.Org!
您还未登录,请登录后查看论坛,或者点击论坛上方的注册链接注册新账号。


发表新主题 回复
精华主题  
主题工具
旧 03-04-30, 23:26 第 1 帖
LYOO
 
LYOO 的头像
 
 
注册会员  
  注册日期: Jan 2003
  帖子: 782
  精华: 37
 

标题: bash脚本调试器


抄来的一个实用的脚本,不过还没完全调通,有兴趣的朋友可以自己改改。

调试器的大体思路是这样:
由bashdb.sh将bashdb.pre与被调试脚本合并成一个debug版脚本临时文件,执行该debug版脚本,通过调用Bush内置的DEBUG的伪信号,来执行bashdb.fns中的相关调试函数。其它细节见脚本中的注释。
上传的附件
文件类型: tar bashdb.tar (10.0 KB, 257 次查看)







__________________
http://211.92.88.40/~lyoo/bookmark/bookmark.html
  LYOO 当前离线   回复时引用此帖
旧 03-05-01, 01:09 第 2 帖
KornLee
 
 
 
★☆★☆★☆★  
  注册日期: Nov 2002
  我的住址: LinuxWorld
  帖子: 6,960
  精华: 61
 

谢谢LYOO兄,如果文件不是很大的话,还是帖出源码来吧~~,这样看着也方便,拷贝粘贴也很便捷,
  KornLee 当前离线   回复时引用此帖
旧 03-05-01, 02:04 第 3 帖
KornLee
 
 
 
★☆★☆★☆★  
  注册日期: Nov 2002
  我的住址: LinuxWorld
  帖子: 6,960
  精华: 61
 

是不是用shell的内置函数eval也可以做到呢?!我的思路是这样的:
1,等待用户输入语句命令之类的字符,以{开头,以}结尾.
2,然后交给eval函数,把你所输入的字符/语句,当做eval的[argment],shell就会执行eval [argment] 命令.
3,如果eval返回状态为真,那么再等待用户输入下个{ ...}
4,如果有错误,就显示错误信息.
这样就可以在命令行下调试短小的脚本啦~~
思路归思路,还得多实验,还请LYOO兄指教,看是否行得通?
  KornLee 当前离线   回复时引用此帖
旧 03-05-01, 10:53 第 4 帖
LYOO
 
LYOO 的头像
 
 
注册会员  
  注册日期: Jan 2003
  帖子: 782
  精华: 37
 

eval的这个用法的确比较有趣,可来检查语法错误,但用来跟踪变量值就勉为其难了。另外用bash -n来检查语法已相当方便了。
我想调试器更重要的目的是随时跟踪变量的值(我总是用加echo的方法来跟踪)。执行完某语句后用trap function DEBUG信号产生中断,更灵活,调入的function调试函数,可扩展出更多功能,如echo显示变量当前值,加判断条件等等。
以上是我的个人理解,呵呵,不对之处请大家指正。(尤其我对eval的使用还很生疏)
  LYOO 当前离线   回复时引用此帖
旧 03-05-04, 13:07 第 5 帖
LYOO
 
LYOO 的头像
 
 
注册会员  
  注册日期: Jan 2003
  帖子: 782
  精华: 37
 

高手就是会想,把这些简单的零件组合就成了功能强大的武器了。
终于把它给读通了,学了不少东西。不过这个脚本不能跟踪进入函数,下一步想试着加上跟踪函数的功能,javalee也来一起玩一把?

bashdb.sh负责生成debug档
代码:
#!/bin/bash #bashdb - bash debugger #该脚本将bashbd.pre和目标脚本处理成调试脚本 echo 'bash Debugger version 1.0' _dbname=${0##*/} if (( $# < 1 )); then echo "$_dbname: Usage: $_dbname filename" >&2 exit 1 fi _guineapig=$1 if [ ! -r $1 ]; then echo "$_dbname: Cannot read file '$_guineapig'." >&2 exit 1 fi shift _tmpdir=/tmp _libdir=. _debugfile=$_tmpdir/bashdb.$$ #正在被调试脚本的临时文件 cat $_libdir/bashdb.pre $_guineapig > $_debugfile exec bash $_debugfile $_guineapig $_tmpdir $_libdir "$@"
bashdb.pre负责对被调试函数进行预处理
代码:
#!/bin/bash #bashdb预处理部分 #本文件预处理被调试的shell脚本 #参数: #$1=初始试验脚本的名字 #$2=临时文件所保存在的目录 #$3=bashdb.pre和bashdb.fns被保存的目录 _debugfile=$0 _guineapig=$1 _tmpdir=$2 _libdir=$3 shift 3 source $_libdir/bashdb.fns declare -a _linebp let _trace=0 let _i=1 while read; do _lines[$_i]=$REPLY let _i=$_i+1 done < $_guineapig trap _cleanup EXIT let _steps=1 LINENO=-2 trap '_steptrap $LINENO' DEBUG
bashdb.fns包含了DEBUG调用的调试函数
代码:
#!/bin/bash #测试脚本的每行被执行之后,shell进入本函数 function _steptrap { _curline=$1 #当前运行行的行号 (( $_trace )) && _msg "$PS4 line $_curline: ${_lines[$_curline]}" if (( $_steps >= 0 )); then let _steps=$_steps-1 fi #首先查看是否达到行编号断点 #如果达到,则进入调试器 if _at_linenumbp ; then _msg "Reached breakpoint at line $_curline" _cmdloop #如果没有达到,则检查是否有中断条件存在且为真 #如果是,则进入调试器 elif [ -n "$_brcond" ] && eval $_brcond; then _msg "Bread condition $_brcond true at line $_curline" _cmdloop #如果不是,则检查是否在采用步进方式,步数是否达到。如果是,则进入调试器 elif (( $_steps == 0 )); then _msg "Stopped at line $_curline" _cmdloop fi } #调试器命令循环 function _cmdloop { local cmd args while read -e -p "bashdb> " cmd args; do case $cmd in h ) _menu ;; #打印命令菜单 bc) _setbc $args ;; #设置中断条件 bp) _setbp $args ;; #设置断点在给定行 cb) _clearbp $args ;; #清除一个或所有断点 ds) _displayscript ;; #列出脚本并显示断点 g ) return ;; #开始/再继续执行脚本 q ) exit ;; #退出 s ) let _steps=${args:-1} #单步执行N次(默认为1) return ;; x ) _xtrace ;; #切换执行追踪 !*) eval ${cmd#!} $args ;; #传递给shell * ) _msg "Invalid command: '$cmd'" ;; esac done } #查看这个行编号是否有一个断点 function _at_linenumbp { local i=0 #循环遍历断点数组并查看它们是否与当前行编号匹配。如果匹配就返回真(0), #否则就返回假 if [ "$_linebp" ]; then while (( $i < ${#_linebp[@]} )); do if (( ${_linebp[$i]} == $_curline )); then return 0 fi let i=$i+1 done fi return 1 } #设置断点在给定的行编号或列出断点 function _setbp { local i #如果无参数,调用断点列表函数。否则查看参数是否为正数 #如果不是,则打印错误消息。如果是,则查看行编号是否包含文本 #如果不是则打印错误信息。如果是,则回应当前断点和新的附加。并将它们 #输送到“排序”,并将结果赋值给断点列表。这将导致断点按数字顺序排列 #注意,使用-u选项可以删除重复的断点 if [ -z "$1" ]; then _listbp elif [ $(echo $1 | grep '^[0-9]*') ]; then if [ -n "${_lines[$1]}" ]; then _linebp=($(echo $( (for i in "${_linebp[*]} $1"; do echo $i; done) | sort -n) )) _msg "Breakpoint set at line $1" else _msg "Breakpoints can only be set on non-blank lines" fi else _msg "Please specify a numeric line number" fi } #列出断点及中断条件 function _listbp { if [ -n "$_linebp" ]; then _msg "Breakpoints at lines: ${_linebp[*]}" else _msg "No breakpoints have been set" fi _msg "Break on condition:" _msg "$_brcond" } #清除单个或所有断点 function _clearbp { local i bps #如果没有参数,那么删除所有断点。否则查看参数是否为正数,如果不是 #则打印错误消息。如果是,则回应除被传递的那个之外的所有当前断点 #并将它们赋值给局部变量。(我们需要这样做是因为将它们赋值给_linebp #将使数组保持在同一大小并将值向回移动一位置,导致重复值)。然后销毁旧数组 #并将局部数组中的元素赋值,于是我们高效地重创了它,减掉了被传递的断点 if [ -z "$1" ]; then unset _linebp[*] _msg "All breakpoints have been cleared" elif [ $(echo $1 | grep '^[0-9]*') ]; then bps=($(echo $(for i in ${_linebp[*]}; do if (( $1 != $i )); then echo $i; fi; done) )) unset _linebp[*] _linebp=(${bps[*]}) _msg "Breakpoint cleared at line $1" else _msg "Please specify a numeric line number" fi } #设置或清除中断条件 function _setbc { if [ -n "$*" ]; then _brcond=$args _msg "Break when true: $_brcond" else _brcond= _msg "Break condition cleared" fi } #打印出shell脚本并标出断点的位置以及当前行 function _displayscript { local i=1 j=0 bp cl ( while (( $i <= ${#_lines[@]} )); do if [ ${_linebp[$j]} ] && (( ${_linebp[$j]} == $i )); then bp='*' let j=$j+1 else bp=' ' fi if (( $_curline == $i )); then cl=">" else cl=" " fi echo "$i:$bp $cl ${_lines[$i]}" let i=$i+1 done ) | more } #切换执行追踪on/off function _xtrace { let _trace="! $_trace" _msg "Execution trace " if (( $_trace )); then _msg "on" else _msg "off" fi } #打印传进来的参数到标准错误 function _msg { echo -e "$@" >&2 } #打印命令菜单 function _menu { _msg 'bashdb commands: bp N set breakpoint at line N bp list breakpoints and break condition bc string set break condition to string bc clear break condition cb N clear breakpoint at line N cb clear all breakpoints ds displays the test script and breakpoints g start/resume execution s [N] execute N statements (default 1) x toggle execution trace on/off h,? print this menu ! string passes string to a shell q quit' } #退出之前删除临时文件 function _cleanup { rm $_debugfile 2>/dev/null }
  LYOO 当前离线   回复时引用此帖
旧 03-05-06, 01:57 第 6 帖
KornLee
 
 
 
★☆★☆★☆★  
  注册日期: Nov 2002
  我的住址: LinuxWorld
  帖子: 6,960
  精华: 61
 

小弟佩服!放在[精华区]收藏啦~~
怎么这两天总也上不来论坛!急死我啦~~
  KornLee 当前离线   回复时引用此帖
旧 03-08-18, 21:02 第 7 帖
alphatan
 
 
 
注册会员  
  注册日期: Aug 2003
  帖子: 18
  精华: 1
 

怎么不把附带的七个限制也一把抄上来?
我也四处找调试bash脚本的工具,可就是没找到,用上面那个的话限制起来不如用echo调试。
少的话不用bashdb也可以了,多了的话用来又说会慢十倍以上,怕怕。这里牛人那么多,怎么不给这些做后辈的用C/C++写个bash脚本的调试器?

此帖于 03-08-18 21:04 被 alphatan 编辑.
  alphatan 当前离线   回复时引用此帖
旧 06-09-19, 11:22 第 8 帖
zipalpha 帅哥
 
zipalpha 的头像
 
 
注册会员  
  注册日期: Jul 2005
  我的住址: 北京东城
  帖子: 32
  精华: 0
 

有一个Bash调式工具在 http://bashdb.sourceforge.net/
大家可以参考下。







__________________
海纳百川,有容乃大;山高万仞,无欲则刚。
我的博客 欢迎指导 http://blog.verycd.com/zipalpha
  zipalpha 当前离线   回复时引用此帖
发表新主题 回复


主题工具

发帖规则
您 [不可以] 发表新主题
您 [不可以] 回复主题
您 [不可以] 上传附件
您 [不可以] 编辑您的帖子

已 [启用] BB 代码
已 [启用] 表情符号
已 [启用] IMG 代码
已 [禁用] HTML 代码
[论坛跳转…]


所有时间均为[北京时间]。现在的时间是 13:13


Powered by vBulletin 版本 3.6.8
版权所有 ©2000 - 2010, Jelsoft Enterprises Ltd.
官方中文技术支持: vBulletin 中文
版权所有 ©2002 - 2009, LinuxSir.Org