孙鑫mfc学习笔记第十三课
2010-08-24 23:26
309 查看
Shell调试技术总结
学习没种语言都会在编写程序中遇到错误,当然shell也不例外。Shell脚本的错误主要可分为两类:第一类是shell脚本中的语法错误,脚本无法执行到底,第二类是shell脚本能够执行完毕,但并不能按照我们预期的结果那样,也就是存在逻辑错误。
第一类错误主要包括漏掉关键字、漏掉引号、空格符该有而未有、变量大小写没去分等。这一类错误一般通过自己的仔细检查都能够检查出来,关键是第二种错误。
在逻辑错误中Shell有几种调试方法。常见的Shell调试方法有trap、tee、调试钩子和Shell选项。
(一)trap是Linux的内建命令,不要用于捕捉信号,trap命令可以指定收集某种信号所执行的命令,基本形式为:
trap command sign1 sign2 、、、signN
对于上述命令的解释为当trap收到sign1 sign2 、、、signN 中的任意一个信号时就执行command命令,当command命令执行完后脚本继续收到信号进行操作,直到脚本执行结束。
Shell脚本在执行时,会产生三个“伪信号”(原因是这三个信号是有Shell产生的,而其他信号是由操作系统产生的),利用trap命令可以捕捉到这三个“伪信号”并输出相关信息是Shell调试的一种重要技巧。三种“伪信号”分别为EXIT、ERR和DEBUG。
Shell伪信号即产生的条件
举例:
1 #!/bin/sh
2 fun()
3 {
4 echo "This is an correct function"
5 var=2011
6 return 0
7 }
8 trap 'echo "Line is $LINENO ,var=$var "' EXIT
9 fun
[root@localhost Shell]# sh trap1
This is an correct function
Line is 1 ,var=2011
这个脚本先执行fun函数然后trap捕捉到EXIT信号后的输出,而EXIT信号是在fun函数执行完毕才产生的。
1 #!/bin/sh
2 fun()
3 {
4 echo "This is an error function"
5 var=2011
6 return 1
7 }
8 trap 'echo "Line is $LINENO ,var=$var "' ERR
9 fun
10 ipconfig
[root@localhost shell]# sh trap2
This is an error function
Line is 6 ,var=2011
trap2: line 10: ipconfig: command not found
Line is 10 ,var=2011
执行该脚本后先执行函数fun,该函数返回1,非零返回值的函数被认为是异常信号,然后trap捕捉到ERR信号然后输出行号和var的值,然后执行ipconfig,ipconfig不存在返回1,因此产生ERR信号故输出如上结果。
1 #!/bin/sh
2
3 trap 'echo "before execute line: $LINENO a=$a,b=$b,c=$c" ' DEBUG
4 a=6
5 b=2
6 c=30
7 while :
8 do
9 if (( $a >= 10 ))
10 then break
11 fi
12 let "a=$a+2"
13 let "b=$b*2"
14 let "c=$c-10"
15 done
[root@localhost shell]# sh trapdebug
before execute line: 4 a=,b=,c=
before execute line: 5 a=6,b=,c=
before execute line: 6 a=6,b=2,c=
before execute line: 7 a=6,b=2,c=30
before execute line: 9 a=6,b=2,c=30
before execute line: 12 a=6,b=2,c=30
before execute line: 13 a=8,b=2,c=30
before execute line: 14 a=8,b=4,c=30
before execute line: 7 a=8,b=4,c=20
before execute line: 9 a=8,b=4,c=20
before execute line: 12 a=8,b=4,c=20
before execute line: 13 a=10,b=4,c=20
before execute line: 14 a=10,b=8,c=20
before execute line: 7 a=10,b=8,c=10
before execute line: 9 a=10,b=8,c=10
before execute line: 10 a=10,b=8,c=10
before execute line: 16 a=10,b=8,c=10
在此脚本中先执行trap先DEBUG然后接着不断的进行跟踪,通过上面运算可以分析到整个脚本的执行踪迹,能够判断吃哪些条件执行了哪些条件没有执行。
trap命令通过捕捉三个“伪信号”能够方便的跟踪异常函数和信号,尽管echo也能实现,但是用trap更加高效、简洁。
(二)用tee命令进行Shell调试。tee命令产生的数据流分为两个,其中将一个输出到标准输出,一个到输出文件。利用tee的这种特性就可以逐步检查各条命令的执行结果来定位错误。tee还有一个选项-a,表示将Shell命令的输出追加到某文件的末尾。
[root@localhost shell]# who |tee output
cherish tty1 Oct 14 11:06 (:0)
cherish pts/0 Oct 14 11:07 (:0.0)
[root@localhost shell]# cat output
cherish tty1 Oct 14 11:06 (:0)
cherish pts/0 Oct 14 11:07 (:0.0)
先将who执行的结果从管道传给tee,tee命令将标准输出复制到文件output。因此仍然输出who命令标准输出。
[root@localhost shell]# ps | tee -a output
PID TTY TIME CMD
6928 pts/0 00:00:00 su
6932 pts/0 00:00:01 bash
29242 pts/0 00:00:00 ps
29243 pts/0 00:00:00 tee
[root@localhost shell]# cat output
cherish tty1 Oct 14 11:06 (:0)
cherish pts/0 Oct 14 11:07 (:0.0)
PID TTY TIME CMD
6928 pts/0 00:00:00 su
6932 pts/0 00:00:01 bash
29242 pts/0 00:00:00 ps
29243 pts/0 00:00:00 tee
将执行结果追加到output文件后边。
1 #!/bin/sh
2 localIP=`cat /etc/sysconfig/network-scripts/ifcfg-eth0 | tee dubug.txt | grep 'IPADDR' | tee -a dubug.txt | cut -d= -f2 | tee -a dubug.txt`
3 echo "the local ip is :$localIP"
[root@localhost shell]# sh tee1
the local ip is :192.168.1.109
[root@localhost shell]# cat dubug.txt
DEVICE=eth0
BOOTPROTO=none
NM_CONTROLLED=yes
ONBOOT=yes
HWADDR=00:0c:29:57:0d:1f
MTU=1500
TYPE=Ethernet
DEFROUTE=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
NAME="System eth0"
UUID=5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03
IPADDR=192.168.1.109
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=8.8.8.8
USERCTL=no
IPADDR=192.168.1.109
192.168.1.109
该脚本中先找出ifcfg-eth0文件内容,然后在dubug.txt后边追加IPADDR内容,最后追加ip地址,从debug.txt可以清晰看出数据的流向。便于发现脚本中存在的逻辑错误。
(三)调试钩子,也称调试块,是源于其他的高级程序语言的调试方法,调试钩子实际上就是一个if/then结构的代码块,DEBUG变量控制该代码是否执行,在程序的开发调试阶段将DEBUG变量设置为TRUE,使其输出调试信息,到了程序交付阶段,将DEBUG设置为FALSE,关闭调试钩子,而无需一一删除调试钩子代码。一般调试钩子就是如下代码块:
1 if [ "$DEBUG" = "true" ]
2 then
3 echo "Debugging information: "
4 、、、、
5 fi
调试钩子中DEBUG是一个全局变量,在开始调试阶段可利用export DEBUG=true 将DEBUG设置为true 。当然上面的代码块在需要许多地方需要调试的情况下非常麻烦,我以我们可以定义一个DEBUG函数使植入调试钩子,这样比较方便。
1 #!/bin/sh
2 DEBUG()
3 {
4 if [ "$DEBUG" = "true" ]
5 then
6 $@
7 fi
8 }
9 a=0
10 b=2
11 c=100
12 DEBUG echo "a=$a b=$b c =$c" #第1个调试钩子
13 while :
14 do
15 DEBUG echo "a=$a b=$b c =$c" #第个调试钩子
16 if (( $a >= 10 ))
17 then
18 break
19 fi
20 let "a=$a+2"
21 let "b=$b*2"
22 let "c=$c-10"
23 done
[root@localhost shell]# export DEBUG=true
[root@localhost shell]# sh debugblock
a=0 b=2 c =100
a=0 b=2 c =100
a=2 b=4 c =90
a=4 b=8 c =80
a=6 b=16 c =70
a=8 b=32 c =60
a=10 b=64 c =50
调试钩子是一个if/else结构。当DEBUG变量为true时,执行所有的位置函数。对于上述脚本先用export命令将DEBUG赋值为true,调试钩子启动执行脚本时不断输出a,b,c三个变量的值,达到最终跟踪变量值变化的目的。这种方法与trap命令捕捉DEBUG信号跟踪变量值方法是等价的。
(四)使用Shell选项。
使用Shelll选项的调试方法是一种不修改源代码的一种方法。在众多Shell选项中,有三个选项可以用于脚本的调试它们是-n、-x、和-c。
Shell的调试选项、简写和意义
举例
1 #!/bin/bash
2 set -x
3 export PATH
4 read -p "Please input (Y/N)"
5 if [ "$yn" == "$Y" ] || [ "$yn" == "$y"]; then
6 echo "ok ,continue";
7 elif [ "$yn" == "$N" ] || [ "$yn" == "$n"]; then
8 echo "oh ,interrupt!";
9 else echo "I don't know what is your choise"
10 fi
[root@localhost shell]# sh else
+ export PATH
+ read -p 'Please input (Y/N)'
Please input (Y/N)y
+ '[' '' == '' ']'
+ echo 'ok ,continue'
ok ,continue
如果脚本中加入了set –x,那么在set命令之后执行的命令以及加在命令行中的任何参数(包括变量和变量的值)都会显示出来。在一行之前都会加上加号(+),提示它是跟踪输出的标致。在子Shell中执行的shell跟踪命令会在一行前面加上两个加号即“++“。
set -参数"表示启用某选项,"set +参数"表示关闭某选项。有时候我们并不需要在启动时用"-x"选项来跟踪所有的命令行,这时我们可以在脚本中使用set命令,这时我们可以在脚本中使用set命令。
set -x #启动"-x"选项
要跟踪的程序段
set +x #关闭"-x"选项
set命令同样可以使用上一节中介绍的调试钩子—DEBUG函数来调用,这样可以避免脚本交付使用时删除这些调试语句的麻烦,如以下脚本片段所示:
DEBUG set -x #启动"-x"选项
要跟踪的程序段
DEBUG set +x #关闭"-x"选项
当然-x也有美中不足的地方,这个时候我们可以利用bash Shell提供的三个有用的内部变量,可以利用-x选项提示符的限制。
Shell用于调试的内部变量及其意义
举例:
1 #!/bin/sh
2 isroot()
3 {
4 if [ "$UID" -ne 0 ]
5 then
6 return 1
7 else
8 return 0
9 fi
10 }
11 echroot()
12 {
13 isroot
14 if [ "$?" -ne 0 ]
15 then
16 echo "I'm not root"
17 else
18 echo "I'm root"
19 fi
20 }而且
21 #对PS4赋值,定制-x选项的提示符
22 export PS4='+{$LINENO: ${FUNCNAME[0]}:${FUNCNAME[1]}}'
23 echroot
[root@localhost shell]# sh -x nestfun
+ export 'PS4=+{$LINENO: ${FUNCNAME[0]}:${FUNCNAME[1]}}'
+ PS4='+{$LINENO: ${FUNCNAME[0]}:${FUNCNAME[1]}}'
+{23: :}echroot
+{13: echroot:main}isroot
+{4: isroot:echroot}'[' 0 -ne 0 ']'
+{8: isroot:echroot}return 0
+{14: echroot:main}'[' 0 -ne 0 ']'
+{18: echroot:main}echo 'I'\''m root'
I'm root
上面的脚本中定义了两个函数isroot和echroot,该脚本对PS4变量重新赋值PS4='+{$LINENO: ${FUNCNAME[0]}:${FUNCNAME[1]}}',即-x选项的提示符显示脚本的行号、当前函数名以及调用函数名。FUNCNAME[0]表示当前函数名,FUNCNAME[1]表示调用函数名。
-c选项使Shell解释器从一个字符串而不是一个脚本文件中读取并执行Shell命令,当需要临时测试一小段脚本的执行结果时可使用。
举例:
[root@localhost shell]# sh -c 'a=2;b=3;let c=$a+$b;echo "$c"'
5
注意:单引号是一个字符串,字符串中包含若干条命令,命令之间用分好隔开。
总结:针对Shell脚本中所遇到的错误进行了分析,对于逻辑错误进行的全面分析,trap能够代替echo方便的用于脚本输出信息,对撼树进行跟踪等。tee运用管道,便于清晰的看出管道间的数据流向,调试钩子借鉴于高级程序语言,是很好的编程风格,Shell选项不改变脚本内容,-n和-x选项是常见的脚本调试手段,-n主要用于脚本语法错误的调试,-x主要用于脚本的逻辑错误的调试。
学习没种语言都会在编写程序中遇到错误,当然shell也不例外。Shell脚本的错误主要可分为两类:第一类是shell脚本中的语法错误,脚本无法执行到底,第二类是shell脚本能够执行完毕,但并不能按照我们预期的结果那样,也就是存在逻辑错误。
第一类错误主要包括漏掉关键字、漏掉引号、空格符该有而未有、变量大小写没去分等。这一类错误一般通过自己的仔细检查都能够检查出来,关键是第二种错误。
在逻辑错误中Shell有几种调试方法。常见的Shell调试方法有trap、tee、调试钩子和Shell选项。
(一)trap是Linux的内建命令,不要用于捕捉信号,trap命令可以指定收集某种信号所执行的命令,基本形式为:
trap command sign1 sign2 、、、signN
对于上述命令的解释为当trap收到sign1 sign2 、、、signN 中的任意一个信号时就执行command命令,当command命令执行完后脚本继续收到信号进行操作,直到脚本执行结束。
Shell脚本在执行时,会产生三个“伪信号”(原因是这三个信号是有Shell产生的,而其他信号是由操作系统产生的),利用trap命令可以捕捉到这三个“伪信号”并输出相关信息是Shell调试的一种重要技巧。三种“伪信号”分别为EXIT、ERR和DEBUG。
Shell伪信号即产生的条件
信号名称 | 产生条件 |
EXIT | 从函数中推出,或从整个脚本中退出 |
ERR | 当一条命令返回非零状态码,即命令执行不成功 |
DEBUG | 脚本中的每条命令执行之前 |
1 #!/bin/sh
2 fun()
3 {
4 echo "This is an correct function"
5 var=2011
6 return 0
7 }
8 trap 'echo "Line is $LINENO ,var=$var "' EXIT
9 fun
[root@localhost Shell]# sh trap1
This is an correct function
Line is 1 ,var=2011
这个脚本先执行fun函数然后trap捕捉到EXIT信号后的输出,而EXIT信号是在fun函数执行完毕才产生的。
1 #!/bin/sh
2 fun()
3 {
4 echo "This is an error function"
5 var=2011
6 return 1
7 }
8 trap 'echo "Line is $LINENO ,var=$var "' ERR
9 fun
10 ipconfig
[root@localhost shell]# sh trap2
This is an error function
Line is 6 ,var=2011
trap2: line 10: ipconfig: command not found
Line is 10 ,var=2011
执行该脚本后先执行函数fun,该函数返回1,非零返回值的函数被认为是异常信号,然后trap捕捉到ERR信号然后输出行号和var的值,然后执行ipconfig,ipconfig不存在返回1,因此产生ERR信号故输出如上结果。
1 #!/bin/sh
2
3 trap 'echo "before execute line: $LINENO a=$a,b=$b,c=$c" ' DEBUG
4 a=6
5 b=2
6 c=30
7 while :
8 do
9 if (( $a >= 10 ))
10 then break
11 fi
12 let "a=$a+2"
13 let "b=$b*2"
14 let "c=$c-10"
15 done
[root@localhost shell]# sh trapdebug
before execute line: 4 a=,b=,c=
before execute line: 5 a=6,b=,c=
before execute line: 6 a=6,b=2,c=
before execute line: 7 a=6,b=2,c=30
before execute line: 9 a=6,b=2,c=30
before execute line: 12 a=6,b=2,c=30
before execute line: 13 a=8,b=2,c=30
before execute line: 14 a=8,b=4,c=30
before execute line: 7 a=8,b=4,c=20
before execute line: 9 a=8,b=4,c=20
before execute line: 12 a=8,b=4,c=20
before execute line: 13 a=10,b=4,c=20
before execute line: 14 a=10,b=8,c=20
before execute line: 7 a=10,b=8,c=10
before execute line: 9 a=10,b=8,c=10
before execute line: 10 a=10,b=8,c=10
before execute line: 16 a=10,b=8,c=10
在此脚本中先执行trap先DEBUG然后接着不断的进行跟踪,通过上面运算可以分析到整个脚本的执行踪迹,能够判断吃哪些条件执行了哪些条件没有执行。
trap命令通过捕捉三个“伪信号”能够方便的跟踪异常函数和信号,尽管echo也能实现,但是用trap更加高效、简洁。
(二)用tee命令进行Shell调试。tee命令产生的数据流分为两个,其中将一个输出到标准输出,一个到输出文件。利用tee的这种特性就可以逐步检查各条命令的执行结果来定位错误。tee还有一个选项-a,表示将Shell命令的输出追加到某文件的末尾。
[root@localhost shell]# who |tee output
cherish tty1 Oct 14 11:06 (:0)
cherish pts/0 Oct 14 11:07 (:0.0)
[root@localhost shell]# cat output
cherish tty1 Oct 14 11:06 (:0)
cherish pts/0 Oct 14 11:07 (:0.0)
先将who执行的结果从管道传给tee,tee命令将标准输出复制到文件output。因此仍然输出who命令标准输出。
[root@localhost shell]# ps | tee -a output
PID TTY TIME CMD
6928 pts/0 00:00:00 su
6932 pts/0 00:00:01 bash
29242 pts/0 00:00:00 ps
29243 pts/0 00:00:00 tee
[root@localhost shell]# cat output
cherish tty1 Oct 14 11:06 (:0)
cherish pts/0 Oct 14 11:07 (:0.0)
PID TTY TIME CMD
6928 pts/0 00:00:00 su
6932 pts/0 00:00:01 bash
29242 pts/0 00:00:00 ps
29243 pts/0 00:00:00 tee
将执行结果追加到output文件后边。
1 #!/bin/sh
2 localIP=`cat /etc/sysconfig/network-scripts/ifcfg-eth0 | tee dubug.txt | grep 'IPADDR' | tee -a dubug.txt | cut -d= -f2 | tee -a dubug.txt`
3 echo "the local ip is :$localIP"
[root@localhost shell]# sh tee1
the local ip is :192.168.1.109
[root@localhost shell]# cat dubug.txt
DEVICE=eth0
BOOTPROTO=none
NM_CONTROLLED=yes
ONBOOT=yes
HWADDR=00:0c:29:57:0d:1f
MTU=1500
TYPE=Ethernet
DEFROUTE=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
NAME="System eth0"
UUID=5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03
IPADDR=192.168.1.109
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=8.8.8.8
USERCTL=no
IPADDR=192.168.1.109
192.168.1.109
该脚本中先找出ifcfg-eth0文件内容,然后在dubug.txt后边追加IPADDR内容,最后追加ip地址,从debug.txt可以清晰看出数据的流向。便于发现脚本中存在的逻辑错误。
(三)调试钩子,也称调试块,是源于其他的高级程序语言的调试方法,调试钩子实际上就是一个if/then结构的代码块,DEBUG变量控制该代码是否执行,在程序的开发调试阶段将DEBUG变量设置为TRUE,使其输出调试信息,到了程序交付阶段,将DEBUG设置为FALSE,关闭调试钩子,而无需一一删除调试钩子代码。一般调试钩子就是如下代码块:
1 if [ "$DEBUG" = "true" ]
2 then
3 echo "Debugging information: "
4 、、、、
5 fi
调试钩子中DEBUG是一个全局变量,在开始调试阶段可利用export DEBUG=true 将DEBUG设置为true 。当然上面的代码块在需要许多地方需要调试的情况下非常麻烦,我以我们可以定义一个DEBUG函数使植入调试钩子,这样比较方便。
1 #!/bin/sh
2 DEBUG()
3 {
4 if [ "$DEBUG" = "true" ]
5 then
6 $@
7 fi
8 }
9 a=0
10 b=2
11 c=100
12 DEBUG echo "a=$a b=$b c =$c" #第1个调试钩子
13 while :
14 do
15 DEBUG echo "a=$a b=$b c =$c" #第个调试钩子
16 if (( $a >= 10 ))
17 then
18 break
19 fi
20 let "a=$a+2"
21 let "b=$b*2"
22 let "c=$c-10"
23 done
[root@localhost shell]# export DEBUG=true
[root@localhost shell]# sh debugblock
a=0 b=2 c =100
a=0 b=2 c =100
a=2 b=4 c =90
a=4 b=8 c =80
a=6 b=16 c =70
a=8 b=32 c =60
a=10 b=64 c =50
调试钩子是一个if/else结构。当DEBUG变量为true时,执行所有的位置函数。对于上述脚本先用export命令将DEBUG赋值为true,调试钩子启动执行脚本时不断输出a,b,c三个变量的值,达到最终跟踪变量值变化的目的。这种方法与trap命令捕捉DEBUG信号跟踪变量值方法是等价的。
(四)使用Shell选项。
使用Shelll选项的调试方法是一种不修改源代码的一种方法。在众多Shell选项中,有三个选项可以用于脚本的调试它们是-n、-x、和-c。
Shell的调试选项、简写和意义
选项名称 | 简写 | 意义 |
noexec | n | 读取脚本中的命令,进行语法检查,但不执行命令 |
xtrace | x | 在执行每个命令之前,将每个命令打印到标准输出(stdout) |
无 | c.. | 从..中读取命令 |
1 #!/bin/bash
2 set -x
3 export PATH
4 read -p "Please input (Y/N)"
5 if [ "$yn" == "$Y" ] || [ "$yn" == "$y"]; then
6 echo "ok ,continue";
7 elif [ "$yn" == "$N" ] || [ "$yn" == "$n"]; then
8 echo "oh ,interrupt!";
9 else echo "I don't know what is your choise"
10 fi
[root@localhost shell]# sh else
+ export PATH
+ read -p 'Please input (Y/N)'
Please input (Y/N)y
+ '[' '' == '' ']'
+ echo 'ok ,continue'
ok ,continue
如果脚本中加入了set –x,那么在set命令之后执行的命令以及加在命令行中的任何参数(包括变量和变量的值)都会显示出来。在一行之前都会加上加号(+),提示它是跟踪输出的标致。在子Shell中执行的shell跟踪命令会在一行前面加上两个加号即“++“。
set -参数"表示启用某选项,"set +参数"表示关闭某选项。有时候我们并不需要在启动时用"-x"选项来跟踪所有的命令行,这时我们可以在脚本中使用set命令,这时我们可以在脚本中使用set命令。
set -x #启动"-x"选项
要跟踪的程序段
set +x #关闭"-x"选项
set命令同样可以使用上一节中介绍的调试钩子—DEBUG函数来调用,这样可以避免脚本交付使用时删除这些调试语句的麻烦,如以下脚本片段所示:
DEBUG set -x #启动"-x"选项
要跟踪的程序段
DEBUG set +x #关闭"-x"选项
当然-x也有美中不足的地方,这个时候我们可以利用bash Shell提供的三个有用的内部变量,可以利用-x选项提示符的限制。
Shell用于调试的内部变量及其意义
变量名称 | 意义 |
LINENO | 表示Shell脚本的行号 |
FUNCNAME | 数组变量,表示整个调用链上所有的函数名 |
PS4 | 设置-x选项的提示符,默认值是“+”符号 |
1 #!/bin/sh
2 isroot()
3 {
4 if [ "$UID" -ne 0 ]
5 then
6 return 1
7 else
8 return 0
9 fi
10 }
11 echroot()
12 {
13 isroot
14 if [ "$?" -ne 0 ]
15 then
16 echo "I'm not root"
17 else
18 echo "I'm root"
19 fi
20 }而且
21 #对PS4赋值,定制-x选项的提示符
22 export PS4='+{$LINENO: ${FUNCNAME[0]}:${FUNCNAME[1]}}'
23 echroot
[root@localhost shell]# sh -x nestfun
+ export 'PS4=+{$LINENO: ${FUNCNAME[0]}:${FUNCNAME[1]}}'
+ PS4='+{$LINENO: ${FUNCNAME[0]}:${FUNCNAME[1]}}'
+{23: :}echroot
+{13: echroot:main}isroot
+{4: isroot:echroot}'[' 0 -ne 0 ']'
+{8: isroot:echroot}return 0
+{14: echroot:main}'[' 0 -ne 0 ']'
+{18: echroot:main}echo 'I'\''m root'
I'm root
上面的脚本中定义了两个函数isroot和echroot,该脚本对PS4变量重新赋值PS4='+{$LINENO: ${FUNCNAME[0]}:${FUNCNAME[1]}}',即-x选项的提示符显示脚本的行号、当前函数名以及调用函数名。FUNCNAME[0]表示当前函数名,FUNCNAME[1]表示调用函数名。
-c选项使Shell解释器从一个字符串而不是一个脚本文件中读取并执行Shell命令,当需要临时测试一小段脚本的执行结果时可使用。
举例:
[root@localhost shell]# sh -c 'a=2;b=3;let c=$a+$b;echo "$c"'
5
注意:单引号是一个字符串,字符串中包含若干条命令,命令之间用分好隔开。
总结:针对Shell脚本中所遇到的错误进行了分析,对于逻辑错误进行的全面分析,trap能够代替echo方便的用于脚本输出信息,对撼树进行跟踪等。tee运用管道,便于清晰的看出管道间的数据流向,调试钩子借鉴于高级程序语言,是很好的编程风格,Shell选项不改变脚本内容,-n和-x选项是常见的脚本调试手段,-n主要用于脚本语法错误的调试,-x主要用于脚本的逻辑错误的调试。
相关文章推荐
- 孙鑫VC++视频学习笔记之8: MFC中指针的获取
- 孙鑫VC学习笔记:第十三讲 (一) 用CArchive类读取与保存文件
- 孙鑫mfc学习笔记第十二课
- 孙鑫mfc学习笔记第十四课
- MFC孙鑫视频学习笔记
- 孙鑫mfc学习笔记第十五课
- 孙鑫VC学习笔记:第十五讲 (四) 编写一个基于MFC对话框的聊天程序
- 孙鑫mfc学习笔记第十六课
- 孙鑫VC学习笔记:第十五讲 编写一个基于MFC对话框的聊天程序
- 孙鑫mfc学习笔记第十七课
- 孙鑫mfc学习笔记第十八课
- 孙鑫mfc学习笔记第十五课
- 孙鑫mfc学习笔记第十九课
- 孙鑫VC学习笔记:第十三讲 用CArchive类读取与保存文件
- 孙鑫mfc学习笔记第四课
- 孙鑫mfc学习笔记第二十课
- [MFC学习笔记]--孙鑫第四课
- MFC视频教程(孙鑫)学习笔记1-Windows程序内部运行原理
- 孙鑫VC学习笔记:第八讲 逃跑按钮的巧妙实现和MFC中指针的获取
- 孙鑫mfc学习笔记第五课