本系列的前面部分清晰地阐明了另外两种 shell 脚本调试模式:详细模式和语法检查模式,并用易于理解的例子展示了如何在这些模式下启用 shell 脚本调试。
<a href="https://linux.cn/article-8028-1.html">如何在 linux 中启用 shell 脚本的调试模式</a>
<a href="https://linux.cn/article-8045-1.html">如何在 shell 脚本中执行语法检查调试模式</a>
shell 跟踪简单的来说就是跟踪 shell 脚本中的命令的执行。要打开 shell 跟踪,请使用 <code>-x</code> 调试选项。
这会让 shell 在终端上显示所有执行的命令及其参数。
我们将使用下面的 <code>sys_info.sh</code> shell 脚本,它会简要地打印出你的系统日期和时间、登录的用户数和系统的运行时间。不过,脚本中包含我们需要查找和更正的语法错误。
<code>#!/bin/bash</code>
<code># script to print brief system info</code>
<code>root_id="0"</code>
<code>date=`date`</code>
<code>no_users=`who | wc -l`</code>
<code>uptime=`uptime`</code>
<code>check_root(){</code>
<code>if [ "$uid" -ne "$root_id" ]; then</code>
<code>echo "you are not allowed to execute this program!"</code>
<code>exit 1;</code>
<code>}</code>
<code>print_sys_info(){</code>
<code>echo "system time : $date"</code>
<code>echo "number of users: $no_users"</code>
<code>echo "system uptime : $uptime</code>
<code>check_root</code>
<code>print_sys_info</code>
<code>exit 0</code>
<code>$ chmod +x sys_info.sh</code>
<code>$ sudo bash -x sys_info.sh</code>

shell 跟踪 - 显示脚本中的错误
从上面的输出我们可以观察到,首先执行命令,然后其输出做为一个变量的值。
例如,先执行 <code>date</code>,其输出做为变量 <code>date</code> 的值。
我们可以执行语法检查来只显示其中的语法错误,如下所示:
<code>$ sudo bash -n sys_info.sh</code>
脚本中语法检查
如果我们审视这个 shell 脚本,我们就会发现 <code>if</code> 语句缺少了封闭条件的 <code>fi</code> 关键字。因此,让我们加上它,新的脚本应该看起来像这样:
<code>#script to print brief system info</code>
<code>fi</code>
再次保存文件并以 root 执行,同时做语法检查:
在 shell 脚本中执行语法检查
上面的语法检查操作的结果仍然显示在脚本的第 21 行还有一个错误。所以,我们仍然要纠正一些语法。
我们将在 <code>echo</code> 命令中添加闭合双引号并保存文件。修改过的脚本如下:
<code>echo "system uptime : $uptime"</code>
现在再一次检查语法。
上面的命令不会产生任何输出,因为我们的脚本语法上正确。我们也可以再次跟踪脚本执行,它应该工作得很好:
跟踪 shell 脚本执行
现在运行脚本。
<code>$ sudo ./sys_info.sh</code>
用 shell 脚本显示日期、时间和运行时间
<a target="_blank"></a>
shell 脚本跟踪可以帮助我们识别语法错误,更重要的是识别逻辑错误。例如,在 <code>sys_info.sh</code> shell 脚本中的 <code>check_root</code> 函数,它用于确定用户是否为 root,因为脚本只允许由超级用户执行。
这里的魔法是由 <code>if</code> 语句表达式 <code>["$ uid" -ne "$ root_id"]</code> 控制的,一旦我们不使用合适的数字运算符(示例中为 <code>-ne</code>,这意味着不相等),我们最终可能会出一个逻辑错误。
假设我们使用 <code>-eq</code> (意思是等于),这将允许任何系统用户以及 root 用户运行脚本,因此是一个逻辑错误。
<code>if [ "$uid" -eq "$root_id" ]; then</code>
注意:我们在本系列开头介绍过,<code>set</code> 这个 shell 内置命令可以在 shell 脚本的特定部分激活调试。
因此,下面的行将帮助我们通过跟踪脚本的执行在其中找到这个逻辑错误:
具有逻辑错误的脚本:
<code>#turning on and off debugging of check_root function</code>
<code>set -x ; check_root; set +x ;</code>
保存文件并调用脚本,在输出中,我们可以看到一个普通系统用户可以在未 sudo 的情况下运行脚本。 这是因为 <code>user_id</code> 的值为 100,不等于为 0 的 root 的 <code>root_id</code> 。
<code>$ ./sys_info.sh</code>
run shell script without sudo
原文发布时间为:2017-01-15
本文来自云栖社区合作伙伴“linux中国”