2.3. Bash 脚本调试

2.3.1. 调试整个脚本

当事情没有按计划进行时,你需要确定到底是什么导致脚本失败。Bash 提供了广泛的调试功能。最常见的是使用以下选项启动子 shell:-x选项,它将以调试模式运行整个脚本。每个命令及其参数的跟踪信息会在命令展开之后、执行之前打印到标准输出。

这是commented-script1.sh脚本在调试模式下运行的示例。再次注意,添加的注释在脚本的输出中是不可见的。

willy:~/scripts> bash -x script1.sh
+ clear

+ echo 'The script starts now.'
The script starts now.
+ echo 'Hi, willy!'
Hi, willy!
+ echo

+ echo 'I will now fetch you a list of connected users:'
I will now fetch you a list of connected users:
+ echo

+ w
  4:50pm  up 18 days,  6:49,  4 users,  load average: 0.58, 0.62, 0.40
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU  WHAT
root     tty2     -                Sat 2pm  5:36m  0.24s  0.05s  -bash
willy	 :0       -                Sat 2pm   ?     0.00s   ?     -
willy	 pts/3    -                Sat 2pm 43:13  36.82s 36.82s  BitchX willy ir
willy    pts/2    -                Sat 2pm 43:13   0.13s  0.06s  /usr/bin/screen
+ echo

+ echo 'I'\''m setting two variables now.'
I'm setting two variables now.
+ COLOUR=black
+ VALUE=9
+ echo 'This is a string: '
This is a string:
+ echo 'And this is a number: '
And this is a number:
+ echo

+ echo 'I'\''m giving you back your prompt now.'
I'm giving you back your prompt now.
+ echo

现在有一个功能齐全的 Bash 调试器,可在 SourceForge 上获取。这些调试功能在大多数现代版本的 Bash 中都可用,从 3.x 版本开始。

2.3.2. 调试脚本的某部分

使用 set Bash 内建命令,你可以对那些你确信没有错误的脚本部分以正常模式运行,而只对有问题的区域显示调试信息。假设我们不确定 w 命令在以下示例中会做什么commented-script1.sh,那么我们可以像这样在脚本中将其包围起来

set -x			# activate debugging from here
w
set +x			# stop debugging from here

输出看起来像这样

willy: ~/scripts> script1.sh
The script starts now.
Hi, willy!

I will now fetch you a list of connected users:

+ w
  5:00pm  up 18 days,  7:00,  4 users,  load average: 0.79, 0.39, 0.33
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU  WHAT
root     tty2     -                Sat 2pm  5:47m  0.24s  0.05s  -bash
willy    :0       -                Sat 2pm   ?     0.00s   ?     -
willy    pts/3    -                Sat 2pm 54:02  36.88s 36.88s  BitchX willyke
willy    pts/2    -                Sat 2pm 54:02   0.13s  0.06s  /usr/bin/screen
+ set +x

I'm setting two variables now.
This is a string:
And this is a number:

I'm giving you back your prompt now.

willy: ~/scripts>

你可以在同一个脚本中多次打开和关闭调试模式。

下表概述了其他有用的 Bash 选项

表 2-1. set 调试选项概述

简写完整写法结果
set -fset -o noglob禁用使用元字符进行文件名生成(通配符展开)。
set -vset -o verbose打印读取的 shell 输入行。
set -xset -o xtrace在执行命令之前打印命令跟踪。

短划线用于激活 shell 选项,加号用于停用它。不要被这个搞糊涂了!

在下面的示例中,我们在命令行上演示这些选项

willy:~/scripts> set -v

willy:~/scripts> ls
ls 
commented-scripts.sh	script1.sh

willy:~/scripts> set +v
set +v

willy:~/scripts> ls *
commented-scripts.sh    script1.sh

willy:~/scripts> set -f

willy:~/scripts> ls *
ls: *: No such file or directory

willy:~/scripts> touch *

willy:~/scripts> ls
*   commented-scripts.sh    script1.sh

willy:~/scripts> rm *

willy:~/scripts> ls
commented-scripts.sh    script1.sh

或者,这些模式可以在脚本本身中指定,通过将所需的选项添加到第一行 shell 声明中。选项可以组合使用,这通常是 UNIX 命令的惯例

#!/bin/bash-xv

一旦你找到了脚本中出错的部分,你可以在每个你不确定的命令之前添加 echo 语句,这样你就可以确切地看到哪里出了问题以及为什么会出错。在示例commented-script1.sh脚本中,可以这样做,仍然假设显示用户给我们带来了问题

echo "debug message: now attempting to start w command"; w

在更高级的脚本中,可以插入 echo 来显示脚本中不同阶段的变量内容,以便检测缺陷

echo "Variable VARNAME is now set to $VARNAME."