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

第一章:The Missing Code Library--13.调试Shell脚本

2012-12-13 13:04 381 查看
虽然这节并不包含一个真实的脚本,但是在此谈谈开发和调试shell脚本的基础是很有益处的。因为,bug是一定会出现的。我发现的最好的调试策略就是渐增性的生成脚本。一部分脚本程序员对于首次运行即会OK保持着高度乐观的态度,但我发现由小处开始,在一个适宜的规模上的,会很有用处。此外,自由使用echo语句来追踪变量,以及-x选项来显示调试输出,都是很有用的。为了看看它们是怎么做的,我们来调试一个简单的猜数字游戏。

代码:

#!/bin/sh
# hilow -- A simple number-guessing game

biggest=100                           # maximum number possible
guess=0                               # guessed by player
guesses=0                             # number of guesses made
number=$(($$ % $biggest)              # random number, between 1 and $biggest

while [ $guess -ne $number ] ; do
echo -n "Guess? " ; read answer
if [ "$guess" -lt $number ] ; then
echo "... bigger!"
elif [ "$guess" -gt $number ] ; then
echo "... smaller!
fi
guesses=$(($guesses + 1)
done

echo "Right!! Guessed $number in $guesses guesses."

exit 0


运行脚本:
调试这个脚本的第一步就是测试下确定生成的数字是完全随机的。我们要获得正在运行的这个脚本所在shell的进程ID,使用$$,然后用%将它减少到一个可以使用的范围内。为了测试这个功能,先直接在命令行上键入:

echo $(($$%100))
43
echo $(($$%100))
43
echo $(($$%100))
43


可以运行,但不怎么随机。为什么?当命令直接在命令行上运行时,PID(进程ID)总是相同的。当在一个脚本中时,命令每次运行都是在一个不同的子shell中,所以PID会变化。下一步是给这个游戏增加基本的逻辑。生成一个1-100的随机数,玩家猜数字,告诉玩家猜的数字是高了还是低了,直到玩家猜出数字。在键入所有的基本的代码后,是时候运行下脚本了。

./hilow.sh
./hilow.sh: line 19: unexpected EOF while looking for matching `"'
./hilow.sh: line 23: syntax error: unexpected end of file


哈,脚本开发人员的烦恼来了:一个意外的EOF。要搞明白这条信息,回忆下引用起来的信息可能包括换行,所以错误表明在19行并不意味着它就在那儿。它只是说明shell读到那儿,一直错误的匹配引号,除非它能遇到最后一个引号才会停止,此时它意识到一定是哪儿出错了。事实上,19行完全正确:

sed -n 19p hilow.sh
echo "Right!! Guessed $number in $guesses guesses."


因此,问题肯定出现在脚本中之前的位置。从shell中得到的错误信息中,唯一有用的就是:它告诉了你哪个字符匹配错误。所以,我会使用grep来尝试提取那些至少有一个引号的行,然后去掉有2个引号的行:

grep '"' hilow.sh | egrep -v '.*".*".*'
echo "... smaller!


就是它:下引号漏掉了。很容易修复,然后我们接着来:

./hilow.sh
./hilow.sh: line 7: unexpected EOF while looking for matching `)'
./hilow.sh: line 23: syntax error: unexpected end of file


又一个新问题。由于脚本中的括号表达式很少,所以很容易,肉眼雷达就能发现生成随机数时的少了半个括号。

number=$(($$ % $biggest)              # random number, between 1 and $biggest


修正后,再接着运行:

./hilow.sh
Guess? 33
... bigger!
Guess? 66
... bigger!
Guess? 99
... bigger!
Guess? 100
... bigger!
Guess? Ctrl+C


因为100是最大的可能生成的数字了,看来代码中有逻辑错误。这些错误难以察觉,因为没有合适的grep和sed调用来确认错误了。检查代码看看你能不能发现哪儿错了。为了调试这个错误,我准备增加一点echo语句,来输出选定的数字,以及确定我输入的就是正在测试的。有关联的代码是:

echo -n "Guess? " ; read answer
if [ "$guess" -lt $number ] ; then


事实上,当我修改了echo语句,看到了这2行,我意识到了错误:读入的变量是answer,而测试的变量是guess。一个很傻的错误,但不是一个罕见的错误(特别是如果你有拼写起来很奇怪的变量名的话)。修复这个错误,将answer改为guess即可。

运行结果:

./hilow.sh
Guess? 50
... bigger!
Guess? 65
... smaller!
Guess? 55
... smaller!
Guess? 52
... bigger!
Guess? 53
Right!! Guessed 53 in 5 guesses.


分析脚本:
这个脚本中最严重的潜在bug是没有检查输入。输入除了数字以外的任何东西,脚本都会失败。把第5个脚本--合法化整型输入validint.sh调用下,是最好的。

附上最终正确的脚本:

#!/bin/sh
# hilow -- A simple number-guessing game

biggest=                           # maximum number possible
guess=                               # guessed by player
guesses=                             # number of guesses made
number=$(($$ % $biggest))             # random number, between  and $biggest

while [ $guess -ne $number ] ; do
echo -n "Guess? " ; read guess
if [ "$guess" -lt $number ] ; then
echo "... bigger!"
elif [ "$guess" -gt $number ] ; then
echo "... smaller!"
fi
guesses=$(($guesses + ))
done

echo "Right!! Guessed $number in $guesses guesses."

exit
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: