Shell 调试脚本,调试脚本所花费的时间常常比编写代码还要多。所有编程语言都应该实现的一个特性就是在出现始料未及的情况时,能够生成跟踪信息。调试信息可以帮你弄清楚是什么原因使得程序行为异常。每位系统程序员都应该了解Bash提供的调试选项。本章为你展示了这些选项的用法。
实战演练
我们可以利用Bash内建的调试工具或者按照易于调试的方式编写脚本,方法如下所示。
(1) 使用选项-x
,启用shell脚本的跟踪调试功能:
$ bash -x script.sh
运行带有-x
选项的脚本可以打印出所执行的每一行命令以及当前状态。
你也可以使用
sh -x script
。
(2) 使用set -x
和set +x
对脚本进行部分调试。例如:
#!/bin/bash
#文件名: debug.sh
for i in {1..6};
do
set -x
echo $i
set +x
done
echo "Script executed"
在上面的脚本中,只会打印出echo $i
的调试信息,因为使用-x
和+x
对调试区域进行了限制。
该脚本并没有使用上例中的seq
命令,而是用{start..end}
来迭代从start
到end
之间的值。这个语言构件(construct)在执行速度上要比seq
命令略快。
(3) 前面介绍的调试方法是Bash内建的。它们以固定的格式生成调试信息。但是在很多情况下,我们需要使用自定义的调试信息。可以通过定义 _DEBUG
环境变量来启用或禁止调试及生成特定形式的信息。
请看下面的代码:
#!/bin/bash
function DEBUG()
{
[ "_DEBUG" == "on" ] &&@ || :
}
for i in {1..10}
do
DEBUG echo "I is $i"
done
可以将调试功能设置为on
来运行上面的脚本:
$ _DEBUG=on ./script.sh
我们在每一条需要打印调试信息的语句前加上DEBUG
。如果没有把 _DEBUG=on
传递给脚本,那么调试信息就不会打印出来。在Bash中,命令:
告诉shell不要进行任何操作。
工作原理
-x
选项会输出脚本中执行过的每一行。不过,我们可能只关注其中某一部分代码。针对这种情况,可以在脚本中使用set builtin
来启用或禁止调试打印。
set -x
:在执行时显示参数和命令。-
set +x
:禁止调试。 -
set -v
:当命令进行读取时显示输入。 -
set +v
:禁止打印输入。
补充内容
还有其他脚本调试的便捷方法,我们甚至可以巧妙地利用shebang来进行调试。
shebang的妙用
把shebang从#!/bin/bash
改成 #!/bin/bash -xv
,这样一来,不用任何其他选项就可以启用调试功能了。
如果每一行前面都加上+
,那么就很难在默认输出中跟踪执行流程了。可以将环境变量PS4设置为'$LINENO:'
,显示出每行的行号:
PS4='$LINENO: '
调试的输出信息可能会很长。如果使用了-x
或set -x
,调试输出会被发送到stderr
。可以使用下面的命令将其重定向到文件中:
sh -x testScript.sh 2> debugout.txt
Bash 4.0以及后续版本支持对调试输出使用自定义文件描述符:
exec 6> /tmp/debugout.txt
BASH_XTRACEFD=6