trap 命令
基本格式: trap command sig1 sig2 ... sigN
有3种信号可以捕获:
EXIT : 从函数中退出, 或整个脚本执行完毕
ERR: 当一条命令返回非0状态码, 即命令执行不成功
DEBUG: 脚本汇总每一条命令执行前
演示 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
运行结果如下:
演示: EXIT (一般使用这个方法来判断某一个函数是否成功执行)
#!/bin/bash
func1()
{
echo "This is an correct function "
var=2010
return 0
}
trap 'echo "Line:$LINENO, var=$var"' EXIT #这个语句表示, 如果下边的fun1正确执行, 那么这里就显示 var=$var的值(20)
fun1
演示: ERR
#!/bin/bash
func2()
{
echo "This is an error function"
var=2010
return 1
}
trap 'echo "Line: $LINENO, var=$var"' ERR #这个语句表示, 如果下边的fun2是否为错误执行, 那么这里就显示 var=$var的值(20)
func2
调试钩子
调试钩子源自于高级程序设计语言中的方法, 实际上是一个if/then结构代码块, DEBUG变量控制该代码块是否执行, 在程序开发调试阶段,
讲DEBUG变量设置为TRUE, 使其输出调试信息, 到了程序交付使用阶段, 讲DEBUG设置为FALSE, 关闭调试钩子, 而无需一一删除调试钩子代码,
if [ "$DEBUG" = "true" ]
then
echo "Debugging information"
fi
调试钩子中的DEBUG是一个全局变量, 在开发调试阶段, 可以利用export DEBUG=true 命令将DEBUG设置为true, 如果在每一处都需要输出调试
信息的地方均使用if/then结构来判断DEBUG变量的值, 显的比较繁琐, 我们可以通过定义一个DEBUG函数使植入调试钩子的过程更为简洁:
#!/bin/bash
DEBUG()
{
if [ "$DEBUG" = "true" ]
then
$@
fi
}
执行脚本前, 先 export DEBUG=true, 然后执行./脚本名
使用shell选项 (跟我之前知道几乎一样)
sh -n 脚本名 : 读取脚本中的命令, 进行语法检查, 但是并执行这些命令
sh -x 在执行每个命令之前, 讲每个命令打印到标准输出(好用, 首选调试工具, 一般与trap的DEBUG共同使用, 这样既可以输出实际执行的每一行命令, 又
可以逐行跟踪变量的值, 而且trap与这个-x都是在标准输出, 所以自动配合的非常好)
-x 选项以 "+"符号作为提示符表示调试信息, 显得美中不足, 如果提示符能包含一些重要信息, 对调试更有帮助, 那么, 我们能否定制-x选项的提示符呢?
答案是肯定的.
LINENO 表示shell脚本的行号
FUNCNAME 数组变量, 表示整个调用链上所有的函数名
PS4 设置-x选项的提示符, 默认是"+"符号
我们可以通过设置PS4, 使得-x选项提示符能包含LINENO和FUNCNAME等丰富的信息, 例如:
(下图是 sh-x 与 trap DEBUG 一起使用)
例如:
#!/bin/bash
isroot()
{
if [ "$UID" -ne 0 ]
then
return 1
else
return 0
fi
}
echoroot()
{
isroot
if [ "$?" -ne 0 ]
then
echo "I am not root user!"
else
echo "root user!"
fi
}
export PS4='+{$LINENO:${FUNCNAME[0]}:${FUNCNAME[1]}}' #这里的PS4是, 显示本行号, 当前函数名, 调用当前函数的函数名
exchoroot
(下图只是展示 PS4, 没有设置 trap DEBUG 功能)