您的位置:首页 > 运维架构 > Shell

shell脚本的调试(trap、tee、shell选项)

2016-05-31 11:37 686 查看
shell脚本的调试,主要有4种:trap命令、tee命令、调试钩子和shell选项

一.使用trap命令

1.基本格式

trap command sig1 sig2....

功能描述:trap命令收到指定信号sign(EXIT,ERR,DEBUG)时,执行command

2.shell脚本的三种“伪信号”

“伪信号”是因为这三个信号是由Shell产生的,其他的信号都是由操作系统产生

EXIT          :从函数中退出,或整个脚本执行完毕

ERR           :当一条命令返回非零状态码,即命令执行不成功

DEBUG     :脚本中的每一条命令执行之前

3.举例:

例1:利用trap命令捕捉DEBUG信号来跟踪变量的取值变化

#!/bin/bash

trap 'echo "before execute line:$LINENO,a=$a,b=$b,c=$c"' DEBUG

a=0
b=2
c=100
while :
do
if ((a >= 10))
then
break
fi
let "a=a+2"
let "b=b*2"
let "c=c-10"

done


运行部分结果:

[root@nn shell]# ./trapdebug.sh
before execute line:5,a=,b=,c=
before execute line:6,a=0,b=,c=
before execute line:7,a=0,b=2,c=
before execute line:8,a=0,b=2,c=100
before execute line:10,a=0,b=2,c=100
before execute line:14,a=0,b=2,c=100
before execute line:15,a=2,b=2,c=100
before execute line:16,a=2,b=4,c=100
before execute line:8,a=2,b=4,c=90
before execute line:10,a=2,b=4,c=90
before execute line:14,a=2,b=4,c=90
before execute line:15,a=4,b=4,c=90
before execute line:16,a=4,b=8,c=90
before execute line:8,a=4,b=8,c=80
before execute line:10,a=4,b=8,c=80
before execut


解析:根据DEBUG产生的条件(脚本中的每一条命令执行之前产生DEBUG信号),因此,每当执行一个语句之前trap捕捉到DEBUG信号,进而打印a b c的值

例2:利用trap命令捕捉EXIT信号跟踪函数结束

#!/bin/bash

fun1()
{
echo "this is an correct function"
var=2010
return 0

}

trap 'echo "Line:$LINENO,var=$var"' EXIT
fun1
运行结果:

[root@nn shell]# ./trapexit.sh

this is an correct function

Line:1,var=2010

例3:利用trap命令捕捉ERR信号

#!/bin/bash

trap 'echo "Line:$LINENO,var=$var"' ERR
fun2()
{
echo "this is an err function"
var=2010
return 1

}

fun2
ipll


运行结果:

[root@nn shell]# ./traperr.sh
this is an err function
Line:9,var=2010
./traperr.sh: line 14: ipll: command not found
Line:14,var=2010
代码解析:

fun2函数返回值是1,非零返回值的函数都被认为是异常函数,因此在调用fun2函数时会产生ERR信号,输出

Line:9,var=2010
下面执行ipll,但是这个是错误语句,因此也会产生ERR信号

二、使用tee命令

使用tee命令可以将管道的东西写进文件

下面举个例子就可以看出tee的作用了:

tee -a file    将标准输出追加到文件末尾,而不会覆盖file

[root@nn shell]# cat /etc/sysconfig/network-scripts/ifcfg-br0 |grep IPADDR | cut -d= -f2
192.168.40.223
[root@nn shell]# cat /etc/sysconfig/network-scripts/ifcfg-br0 |tee /home/a.txt|grep IPADDR |tee -a /home/a.txt | cut -d= -f2
192.168.40.223
[root@nn shell]# cat /home/a.txt
DEVICE=br0
NM_CONTROLLED=no
TYPE=Bridge
ONBOOT=yes
BOOTPROTO=none
IPADDR=192.168.40.223
GATEWAY=192.168.40.1
NETMASK=255.255.255.0
DNS1=192.168.10.11
DEFROUTE=yes
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
NAME="br0"
IPADDR=192.168.40.223
[root@nn shell]#

三、使用调试钩子

其实与一相似,不再多写

四、使用shell选项

前面三种方法都是通过修改shell脚本源代码,来定位错误,使用shell选项是一种不修改源代码也能定位错误信息

1.set   -n      :只进行语法检测,并不会真正执行代码

#!/bin/bash

set -n #set -o noexec 与set -n等价

echo "starting...."

var=0;
while :
if [ $var -gt 3 ]
then
break

fi
let "var=var+1"
done
运行结果:
[root@nn shell]# chmod +x misskey.sh
[root@nn shell]# ./misskey.sh
./misskey.sh: line 15: syntax error near unexpected token `done'
./misskey.sh: line 15: `done'


当然你也可以利用sh 命令直接对脚本进行语法检测     语法:  sh -n 脚本文件
#!/bin/bash

echo "starting...."

var=0;
while :
if [ $var -gt 3 ]
then
break

fi
let "var=var+1"
done
运行结果:
[root@nn shell]# sh -n ./misskey.sh    
./misskey.sh: line 14: syntax error near unexpected token `done'
./misskey.sh: line 14: `done'


2. -x
在执行每个命令之前,将每个命令打印到标准输出

#!/bin/bash

echo "starting...."

var=0;
while :
do
if [ $var -gt 3 ]
then
break

fi
let "var=var+1"
echo var=$var
done


运行结果:
[root@nn shell]# sh -x ./misskey.sh
+ echo starting....
starting....
+ var=0
+ :
+ '[' 0 -gt 3 ']'
+ let var=var+1
+ echo var=1
var=1
+ :
+ '[' 1 -gt 3 ']'
+ let var=var+1
+ echo var=2
var=2
+ :
+ '[' 2 -gt 3 ']'
+ let var=var+1
+ echo var=3
var=3
+ :
+ '[' 3 -gt 3 ']'
+ let var=var+1
+ echo var=4
var=4
+ :
+ '[' 4 -gt 3 ']'
+ break


3.shell用于调试的内部变量
LINENO     :表示shell脚本的行号

FUNCNAME     :数组变量,表示整个调用链上所有的函数名   #FUNCNAME[0]:表示当前正在运行的函数,FUNCNAME[1]:表示调用函数$FUNCNAME[0]的函数名字

PS4      :设置-x选项的提示符。默认值是“+”号       ;#export PS4=   

4.-c 

[root@nn shell]# a=10;b=20;c=$a*$b;echo $c
10*20
[root@nn shell]# a=10;b=20;let c=$a*$b;echo $c
200
[root@nn shell]# sh -c 'a=10;b=20;let c=$a*$b;echo $c'
200
sh -c实际上就是将后面的字符串作为命令来执行,一个字符串可以包含多个命令,命令之间需要用分号隔开
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息