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实际上就是将后面的字符串作为命令来执行,一个字符串可以包含多个命令,命令之间需要用分号隔开