对于厌烦了的 print 和 echo,可以尝试点新鲜省力的小手段。
1. 使用 shell 的执行选项
sh 和 bash 常用的执行指令有:-n、-x、-c、-v。
其中:
-n 是 noexec 的简写,作用是只做脚本的语法检查,而不执行脚本。
-x 是 xtrace 的简写,作用是在每一行代码执行之前,将代码本身打印到标准输出(代码前添加一个 “+” 用来区别)。这个在调试的时候尤其有用。
-c 是 command string 的缩写,使用该选项从字符串而不是文件读取脚本。比如,sh -c 'a=1;b=2;let c=$a+$b;echo "c=$c"'。
-v 是 verbose 的缩写,用来显示所有读入的标准输入。
这些选项除了在启动脚本时指定外,我们还可以在脚本中,使用 set 来设置。比如,在脚本中,我们可以用 set 来打开和关闭 xstrace:
set -x #启动"-x"选项 要跟踪的程序段 set +x #关闭"-x"选项
2. 用 trap 设置调试陷阱
trap 是可以接收指定的 SIGNAL ,然后,执行设定的脚本。除了我们使用 kill -l 罗列的那些 SIGNAL,还有三个虚拟的 SIGNAL:EXIT,ERR,DEBUG。前两个不必说,第三个是每执行一条指令都会发出的。。。所以,我们可以借助 DEBUG 来跟踪变量。如下,我们可以在脚本中添加这么一行代码:
trap 'echo "line:$LINENO, a=$a"' DEBUG
然后,脚本每执行一行,都会打印相应行号,以及 a 的值。。。当然,除了变量 a ,你可以随意指定要要追中的变量。比如,下面这个例子:
1 #!/bin/bash 2 3 trap 'echo "line:$LINENO, str=$str, str1=$str1"' DEBUG 4 5 str="abcdefg" 6 7 str1=$(expr substr "$str" 1 3) 8 9 echo $str1 10 11 if [ $str1 == "abc" ] ;then 12 echo "nice" 13 fi
执行的结果如下:
line:5, str=, str1= line:7, str=abcdefg, str1= line:9, str=abcdefg, str1=abc abc line:11, str=abcdefg, str1=abc line:12, str=abcdefg, str1=abc nice
主意,因为这里只有 5、7、9 、11、12 这几行有代码,所以~
3. 用 tee 来调试管道
有时候我们需要调试管道。。。比如下面这条,套了好几层,也不知道谁对谁错。。。一条条的试?好像也比较麻烦。
tee 的作用呢,是当标准输入有数据时,把数据转到标准输出的同时,把数据写到某文件中。比如:
ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | tee temp.txt | cut -d : -f3 | awk '{print $1}'` echo $ipaddr
tee 这一段,完全就是为了查看中间输出了什么。。。执行完这一句,在当前目录多了一个 temp.txt 的文件,内容是:
$ cat temp.txt inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0
so...
4. 使用调试钩子
这个完全就是用普通代码完成的小技巧,相信其他语言编程的时候,这样的代码也常用的。在 shell 中实现出来大概是这样的:
if [ “$DEBUG” = “true” ]; then echo “debugging” #此处可以输出调试信息 fi
用这段代码,我们可以方便的用一个名为 DEBUG 的变量控制是否输出调试信息;设置 'export DEBUG=true' 就可以打开调试输出。或者,我们可以定一个 DEBUG 函数:
DEBUG() { if [ "$DEBUG" = "true" ]; then $@ fi } a=1 DEBUG echo "a=$a" if [ "$a" -eq 1 ] ;then b=2 else b=1 fi DEBUG echo "b=$b" c=3 DEBUG echo "c=$c"
发布的时候,记得把调试开关关了,留着代码,也没多大影响。