脚本总会窝藏着一些臭虫,抓虫也是平常工作的一个重要组成部分,学会善长调试势必会让工作变得轻松。然而你平常是不是已经厌倦且无奈于你那唯一的通过插入echo语句输出信息的穷办法。好,是的,我厌倦了。
在介绍如何高效调试之前,先推荐一个vim的插件,bash-support(slogan:Make Vim as Your Bash-IDE Using bash-support Plugin)。使用它,是因为至少我已经厌倦了每次写脚本的时候,重复第一个动作,包含解释器路径(#!/bin/bash)。欢迎大家踊跃尝试。
我不得不重申我上面提到的厌倦了胡乱插入echo语句来调试脚本,因为只有当你不想这样才会想办法去改变它。那么我们正确调试脚本的顺序应该是怎样的呢?
1)通过参数-n 检查脚本的语法正确性,如:sh -n test_201.sh
2)通过参数-x 来跟踪脚本的执行,如 sh -x test_201.sh
3)从上面使用-x来跟踪调试脚本输出的内容,只有每一条实际执行的命令以及行首的一个“+”号提示符。这个“+”号实在没有多大的意义,且显示的加号是受什么控制的呢?能否定制它?有了这个疑问后,当你输入如下“echo $PS4”时,恐怕你此时已经有所察觉了。我们可以修改 export PS4='+{$LINENO:${FUNCNAME[0]}} '来增强-x。再来看输出:
上面介绍的几种方法对于脚本是“无侵害”的,下面再介绍几种“侵害型”的,即对脚本进行修改。
1)相对于sh -x 跟踪整个脚本的执行,我们可以把影响范围缩小到某段代码,如
set -x #启动“-x"选项
# ba la ba la
set +x #关闭”-x"选项
2)相对于set -x ,我觉得一种实际上更应该成为脚本编写范式的做法是“使用调试钩子",定义DEBUG函数,在需要加入调试信息的地方,调用DEBUG,即如下
DEBUG()
{
if [ "$DEBUG" = "true" ]; then
$@
fi
}
也可以这样使用 DEBUG set -x
3)使用trap命令
trap命令用于捕获指定的信号并执行预定义的命令,其基本语法为: trap 'command' signal, signal 有DEBUG,EXIT
使用场景:我们想跟踪函数的退出状态,在函数退出时,输出某些想要跟踪的变量的值
在脚本中加入 trap ' echo "after exit the function: ${FUNCNAME[0]}, a=$a, b=$b, c=$c" ' EXIT
比如我们想在执行每条命令的时候
在脚本中加入 trap ' echo “before execute the line: $LINENO, a=$a, b=$b, c=$c" ' DEBUG
4) 只使用trap ’command‘ debug,输出还是不直观,因为我们不记得脚本12行是什么?所以最好是既跟踪每一行相关变量的值,也输出实际执行的每一条命令(-x 参数你还记得吧?)。即:
另外:如果你的脚本足够的复杂的话,应考虑使用更加强大的shell调试器bashdb。