如何在Shell脚本中跟踪调试命令的执行

系统 Linux
在 shell 脚本调试系列 中,本文将解释第三种 shell 脚本调试模式,即 shell 跟踪,并查看一些示例来演示它如何工作以及如何使用它。

[[182102]]

在 shell 脚本调试系列 中,本文将解释第三种 shell 脚本调试模式,即 shell 跟踪,并查看一些示例来演示它如何工作以及如何使用它。

本系列的前面部分清晰地阐明了另外两种 shell 脚本调试模式:详细模式和语法检查模式,并用易于理解的例子展示了如何在这些模式下启用 shell 脚本调试。

  1. 如何在 Linux 中启用 Shell 脚本的调试模式
  2. 如何在 Shell 脚本中执行语法检查调试模式

shell 跟踪简单的来说就是跟踪 shell 脚本中的命令的执行。要打开 shell 跟踪,请使用 -x 调试选项。

这会让 shell 在终端上显示所有执行的命令及其参数。

我们将使用下面的 sys_info.sh shell 脚本,它会简要地打印出你的系统日期和时间、登录的用户数和系统的运行时间。不过,脚本中包含我们需要查找和更正的语法错误。

  1. #!/bin/bash 
  2. # script to print brief system info 
  3. ROOT_ID="0" 
  4. DATE=`date
  5. NO_USERS=`who | wc -l` 
  6. UPTIME=`uptime` 
  7. check_root(){ 
  8.   if [ "$UID" -ne "$ROOT_ID" ]; then 
  9.     echo "You are not allowed to execute this program!" 
  10.     exit 1;     
  11. print_sys_info(){ 
  12.   echo "System Time    : $DATE" 
  13.   echo "Number of users: $NO_USERS" 
  14.   echo "System Uptime  : $UPTIME 
  15. check_root 
  16. print_sys_info 
  17. exit 0 

保存文件并执行脚本。脚本只能用 root 用户运行,因此如下使用 sudo 命令运行:

  1. $ chmod +x sys_info.sh 
  2. $ sudo bash -x sys_info.sh    

shell 跟踪 - 显示脚本中的错误 

shell 跟踪 - 显示脚本中的错误

从上面的输出我们可以观察到,首先执行命令,然后其输出做为一个变量的值。

例如,先执行 date,其输出做为变量 DATE 的值。

我们可以执行语法检查来只显示其中的语法错误,如下所示:

  1. $ sudo bash -n sys_info.sh  

 

 

脚本中语法检查 

脚本中语法检查

如果我们审视这个 shell 脚本,我们就会发现 if 语句缺少了封闭条件的 fi 关键字。因此,让我们加上它,新的脚本应该看起来像这样:

  1. #!/bin/bash 
  2. #script to print brief system info 
  3. ROOT_ID="0" 
  4. DATE=`date
  5. NO_USERS=`who | wc -l` 
  6. UPTIME=`uptime` 
  7. check_root(){ 
  8.   if [ "$UID" -ne "$ROOT_ID" ]; then 
  9.     echo "You are not allowed to execute this program!" 
  10.     exit 1; 
  11.   fi     
  12. print_sys_info(){ 
  13.   echo "System Time    : $DATE"  
  14.   echo "Number of users: $NO_USERS" 
  15.   echo "System Uptime  : $UPTIME 
  16. check_root 
  17. print_sys_info 
  18. exit 0 

再次保存文件并以 root 执行,同时做语法检查: 

  1. $ sudo bash -n sys_info.sh  

在 shell 脚本中执行语法检查 

在 shell 脚本中执行语法检查

上面的语法检查操作的结果仍然显示在脚本的第 21 行还有一个错误。所以,我们仍然要纠正一些语法。

再一次分析脚本,会发现第 21 行的错误是由于在 print_sys_info 函数内***一个 echo 命令中没有闭合双引号 "。

我们将在 echo 命令中添加闭合双引号并保存文件。修改过的脚本如下:

  1. #!/bin/bash 
  2. #script to print brief system info 
  3. ROOT_ID="0" 
  4. DATE=`date
  5. NO_USERS=`who | wc -l` 
  6. UPTIME=`uptime` 
  7. check_root(){ 
  8.   if [ "$UID" -ne "$ROOT_ID" ]; then 
  9.     echo "You are not allowed to execute this program!" 
  10.     exit 1; 
  11.   fi 
  12. print_sys_info(){ 
  13.   echo "System Time    : $DATE" 
  14.   echo "Number of users: $NO_USERS" 
  15.   echo "System Uptime  : $UPTIME" 
  16. check_root 
  17. print_sys_info 
  18. exit 0 

现在再一次检查语法。

  1. $ sudo bash -n sys_info.sh 

上面的命令不会产生任何输出,因为我们的脚本语法上正确。我们也可以再次跟踪脚本执行,它应该工作得很好:

  1. $ sudo bash -x sys_info.sh  

 

 

跟踪 shell 脚本执行 

跟踪 shell 脚本执行

现在运行脚本。

  1. $ sudo ./sys_info.sh  

 

 

用 shell 脚本显示日期、时间和运行时间 

用 shell 脚本显示日期、时间和运行时间

shell 跟踪执行的重要性

shell 脚本跟踪可以帮助我们识别语法错误,更重要的是识别逻辑错误。例如,在 sys_info.sh shell 脚本中的 check_root 函数,它用于确定用户是否为 root,因为脚本只允许由超级用户执行。

  1. check_root(){ 
  2.   if [ "$UID" -ne "$ROOT_ID" ]; then 
  3.     echo "You are not allowed to execute this program!" 
  4.     exit 1; 
  5.   fi 

这里的魔法是由 if 语句表达式 ["$ UID" -ne "$ ROOT_ID"] 控制的,一旦我们不使用合适的数字运算符(示例中为 -ne,这意味着不相等),我们最终可能会出一个逻辑错误。

假设我们使用 -eq (意思是等于),这将允许任何系统用户以及 root 用户运行脚本,因此是一个逻辑错误。

  1. check_root(){ 
  2.   if [ "$UID" -eq "$ROOT_ID" ]; then 
  3.     echo "You are not allowed to execute this program!" 
  4.     exit 1; 
  5.   fi 

注意:我们在本系列开头介绍过,set 这个 shell 内置命令可以在 shell 脚本的特定部分激活调试。

因此,下面的行将帮助我们通过跟踪脚本的执行在其中找到这个逻辑错误:

具有逻辑错误的脚本:

  1. #!/bin/bash 
  2. #script to print brief system info 
  3. ROOT_ID="0" 
  4. DATE=`date
  5. NO_USERS=`who | wc -l` 
  6. UPTIME=`uptime` 
  7. check_root(){ 
  8.   if [ "$UID" -eq "$ROOT_ID" ]; then 
  9.     echo "You are not allowed to execute this program!" 
  10.     exit 1; 
  11.   fi 
  12. print_sys_info(){ 
  13.   echo "System Time    : $DATE" 
  14.   echo "Number of users: $NO_USERS" 
  15.   echo "System Uptime  : $UPTIME" 
  16. #turning on and off debugging of check_root function 
  17. set -x ; check_root;  set +x ; 
  18. print_sys_info 
  19. exit 0 

保存文件并调用脚本,在输出中,我们可以看到一个普通系统用户可以在未 sudo 的情况下运行脚本。 这是因为 USER_ID 的值为 100,不等于为 0 的 root 的 ROOT_ID 。

  1. $ ./sys_info.sh  

 

 

Run Shell Script Without Sudo 

Run Shell Script Without Sudo

未 sudo 的情况下运行 shell 脚本

那么,现在我们已经完成了 shell 脚本调试系列,可以在下面的反馈栏里给我们关于本篇或者本系列提出问题或反馈。

作者简介: 

 

 

[[182103]]

Aaron Kili 是 Linux 和 F.O.S.S 爱好者,将来的 Linux SysAdmin、web 开 发人员,目前是 TecMint 的内容创作者,他喜欢用电脑工作,并坚信分享知识。

责任编辑:庞桂玉 来源: Linux中国
相关推荐

2016-12-20 09:30:22

shell脚本linux

2016-12-16 09:23:29

LinuxShell脚本

2018-02-01 17:32:30

LinuxUNIXBash Shell

2021-08-30 07:50:42

脚本语言命令行

2021-01-18 17:23:30

代码调试VS Code

2011-07-25 16:03:47

XCode 编译

2023-04-04 07:52:26

RedisLua脚本

2021-04-21 08:03:34

脚本Shell读取

2021-08-20 10:46:25

Shell脚本文件Linux

2017-03-10 10:37:16

Linux命令脚本

2020-06-04 17:00:37

Linux命令脚本

2020-12-14 06:57:37

shell

2022-11-23 08:14:42

bash 脚本test 命令

2021-03-14 09:28:24

Linux Shell脚本

2022-12-22 20:47:01

脚本循环结构

2022-10-09 10:18:44

LinuxShell脚本

2024-05-31 12:54:37

.NET CoreLinux语言

2012-05-08 11:11:43

Linuxcrontab命令

2021-02-15 17:29:46

LinuxShell脚本

2011-03-29 09:56:48

Oracle数据库10SQL
点赞
收藏

51CTO技术栈公众号