常见问题
三种类型:
- Syntax Error
- Runtime Error
- Logic Error
- 这三种问题,难度依次增加,第一种问题,可通过对shell脚本进行静态分析,后两种问题则需要动态调试来定位。
调试手段
代码静态检查
虽然静态检查发现的问题,执行的时候也可以暴露出来。但静态检查无需执行脚本,而真正执行的话,可能大错已经铸成了。
shellcheck
一个静态bash脚本检查工具。
ShellCheck is an open source static analysis tool that automatically
finds bugs in your shell scripts.
例子:
shellcheck ./buggy.sh
shell调试选项-n(noexec)
Shell本身提供一些调试方法选项:
- -n,读一遍脚本中的命令但不执行,用于检查脚本中的语法错误
具体使用方式可参考后文shell调试选项一节,同时-n、-v可结合为-nv来使用。
/bin/sh -n ./buggy.sh
如果有问题,上述命令执行后会有错误提示。
借助IDE或编辑器
比如使用vim文本编辑器时,打开语法高亮,可发现一些简单直观的错误。
动态调试
输出信息到标准输出
- echo方法
可以使用echo输出字符串或变量
echo "My name is $name"
- printf方法
printf "%-8s %-14s " $cur_date $ip
shell调试选项-x(xtrace)、-v(verbose)
Shell本身提供一些调试方法选项:
- -v,一边执行脚本,一边将执行过的脚本命令打印到标准输出
- -x,提供跟踪执行信息,将执行的每一条命令和结果依次打印出来。
具体的使用方式有三种:
- 1、在命令行中提供参数:
$bash -x buggy.sh
- 2、脚本开头提供参数:
#!/bin/sh -x #!/bin/sh -xv
- 3、在脚本中用set命令启用或禁用参数:其中set -x表示启用,set +x表示禁用。
格式如下:
set -x echo $i set +x
set -x;BuggyFunction;set +x;
上述三种方法的区别在于,前两种对脚本的所有行都启用了调试模式,第三中方式,仅对部分行启用了调试模式。
bashdb(Bash Debugger)
一个类GDB的调试工具,可以运行断点设置、变量查看等常见调试操作,具体使用方式如下:
$ bashdb --debug test.sh bash debugger, bashdb, release 4.2-0.8
$ bashdb --debug test.sh
bash debugger, bashdb, release 4.2-0.8
shopt -p //查看当前设置情况 shopt -s extdebug //启动extdebug模式 shopt -u extdebug //取消extdebug模式
但shopt依赖于bashdb,如不方便使用,可使用下面的set命令替代shopt绝大部分功能。
set -o errtrace //打开,=set -e或-E set -o functrace //打开,=set -f或-T set +o errtrace //关闭,=set -e或-E set +o functrace //关闭,=set -f或-T
其他技巧
使用一致的调试库
将环境配置、traps、日志等放到my-debug-env中,可以保证一致的调试环境。
### Define Debug environment ### Filename: my-debug-env trap 'echo "$BASH_COMMAND" failed with error code $?' ERR #!/usr/bin/env bash ### Example Script ### Filename: example-debug echo "Example Script..." bad_command &> /dev/null ### Example output with no debug env [me@linux ~]$ ./example-debug Example Script... ### Example output with the debug env [me@linux ~]$ BASH_ENV=./my-debug-env ./example-debug Example Script... bad_command &> /dev/null failed with error code 127
调试陷阱/智能调试(Debugging Hook)
在调试阶段,将_DEBUG置为“on”,开启调试模式;
结束调试之后,_DEBUG=“off” 关闭调试模式。
_DEBUG="on" function DEBUG() { [ "$_DEBUG" == "on" ] && $@ } DEBUG echo "File is $filename" DEBUG set -x Cmd1 Cmd2 DEBUG set +x