十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Shell编程——调试

Shell编程——调试 调试1、常见Shell脚本错误范例1.1、if条件语句缺少结尾关键字1.2、循环语句缺少关键字1.3、成对的符号落了单1.4、中括号两端没空格1.5、Shell语法调试小结2、Shell脚本调试技巧2.1、使用dos2unix命令处理在Windows下开发的脚本2.2、使用echo命令调试2.3、使用bash命令参数调试2.3.1、sh参数-n的测试2.3.2、 sh参数-v的测试2.3.3、sh参数-x的测试2.4、使用set命令调试部分脚本内容2.5、其他调试Shell脚本的工具3、小结1、常见Shell脚本错误范例1.1、if条件语句缺少结尾关键字范例:if条件语句缺少结尾关键字引起的错误。[rootoldboy scripts]# cat 15_1.sh#! /bin/shif[10-lt12]thenechoYes,10 is less than 12执行结果如下[rootoldboy scripts]# sh 15_1.sh15_1.sh: line5: syntax error: unexpected end offile结果给出了提示第5行存在语法错误这不是所期待的意外的文件结尾。根据这个提示我们知道脚本的尾部有问题仔细观察发现原来是缺少了fi结尾。说明在Shell脚本开发中脚本缺少fi关键字是很常见的问题。另外当执行脚本时提示输出错误后不要只看那些提示的错误行而是要观察整个相关的代码段。Shell脚本解释器一般不会对脚本错误进行精确的定位而是在试图结束一个语句时进行错误统计因此掌握语法并养成良好的规范和习惯就显得很重要。1.2、循环语句缺少关键字for、while、until和case语句中的错误是指实际语句段不正确也许是漏写或拼错了固定结构中的一个保留字。范例循环结构语句中缺少关键字引起的错误。[rootoldboy scripts]# cat -n 15_2.sh1#! /bin/sh2whiletrue3do4statuscurl-I-s--connect-timeout10$1|head-1|awk{print $2}5okcurl-I-s--connect-timeout10$1|head-1|cut-d -f36if[$status200][$okOK];the#这里缺了个n应该为then。7echothis url is good8else9echo this url is bad10fi11sleep312done执行结果如下[rootoldboy scripts]# sh 15_2.sh www.baidu.com15_2.sh: line8: syntax error near unexpected tokenelse 15_2.sh: line8:else通过提示可知是第8行的语法错误在“else”附近。经过前后观察可以发现​“the”少加了个“n”​应为“then”​。如果报错的是循环或条件独立的语句对上下关联部分语句也都要看一下。1.3、成对的符号落了单成对的符号有[​]​、()、{}、“”、‘’、等如果它们落了单也会导致一些错误。范例成对的符号双引号落了单导致的错误。[rootoldboy scripts]# cat -n 15_3.sh1#! /bin/sh2DBPATH/server/backup3MYUSERroot4MYPASSoldboy1235SOCKET/data/3306/mysql.sock #这里故意设置成缺引号。 6 MYCMDmysql -u$MYUSER-p$MYPASS-S$SOCKET 7 MYDUMPmysqldump -u$MYUSER-p$MYPASS-S$SOCKET 8 [ ! -d $DBPATH]mkdir$DBPATH9fordbnamein$MYCMD-eshow databases; |sed1,2d|egrep-vmysql|schema10do11$MYDUMP$dbname|gzip$DBPATH/${dbname}_$(date%F).sql.gz12done执行结果如下[rootoldboy scripts]# sh 15_3.sh15_3.sh: line7: unexpected EOFwhilelookingformatching 15_3.sh: line13: syntax error: unexpected end offile我们明明看到是第5行少了个双引号但是报错的是第7行。原因是第7行和第13行调用了第5行的sock路径。范例成对的符号中括号落了单导致的错误。[rootoldboy scripts]# cat -n 15_4.sh1#! /bin/sh2DBPATH/server/backup3MYUSERroot4MYPASSoldboy1235SOCKET/data/3306/mysql.sock6MYCMDmysql -u$MYUSER-p$MYPASS-S$SOCKET7MYDUMPmysqldump -u$MYUSER-p$MYPASS-S$SOCKET8[!-d$DBPATHmkdir$DBPATH#这里缺了个后半个中括号“]”。9fordbnamein$MYCMD-eshow databases; |sed1,2d|egrep-vmysql|schema10do11$MYDUMP$dbname|gzip$DBPATH/${dbname}_$(date%F).sql.gz12done执行结果如下[rootoldboy scripts]# sh 15_4.sh15_4.sh: line8:[: missing ]#这个错误提示很准。1.4、中括号两端没空格范例中括号两端没空格导致的错误。[rootoldboy scripts]# cat -n 15_5.sh1#! /bin/bash2#created by oldboy3a34b15if[$a-lt$b]#中括号表达式两端无空格。6then7echoYes,$a$b8else9echoYes,$a$b10fi执行结果如下[rootoldboy scripts]# sh 15_5.sh15_5.sh: line5:[3:commandnot found Yes,3 11.5、Shell语法调试小结Shell的语法调试并不是很智能报错也不是很精准因此就需要我们在开发规范和书写脚本上多下工夫企业里的Shell脚本大多都是比较短的因此开发起来也相对轻松。如果能在开发过程中重视书写习惯、开发规范和开发制度那么就会减少脚本调试的难度和次数提升开发效率。此外要对Shell的基本语法十分熟练这样才能更好地利用脚本调试。此外写脚本的思路要清晰否则将给调试带来困难。可采用的思路如下首先思考开发框架尽量模块化开发复杂的脚本要简单化、分段实现。并采用打游戏的思想第一关、第二关、第三关去完善框架结构。然后利用函数分模块开发语法结构如下函数1()函数2()main()main $#执行主函数。需要注意的是不要强制模块化分块要合理。2、Shell脚本调试技巧2.1、使用dos2unix命令处理在Windows下开发的脚本范例将Windows下编辑的脚本放置到Linux下执行的案例。将Windows下编辑的脚本放置到Linux下执行的情况如下[rootoldboy scripts]# cat -v while.sh#! /bin/bash# this script is created by oldboy.#! /bin/sh^Mi1^Msum0^Mwhile((i 100))^M do^M((sumsumi))^M((i))^M done^Mprintftotalsum is :$sum\n^M[rootoldboy scripts]# sh while.shwhile.sh: line 10: syntax error near unexpected token while.sh: line10: while((i 100))你可能会发现对于在Windows下开发的脚本明明经检查没有发现问题但就是在执行时会出现莫名其妙的语法错误。这时最好执行dos2unix格式化一下。执行dos2unix格式化是一个很好的习惯。[rootoldboy scripts]# dos2unix while.sh #使用dos2unix格式化后的结果。dos2unix: convertingfilewhile.sh to UNIXformat...[rootoldboy scripts]# cat -v while.sh#! /bin/bash# this script is created by oldboy.# function:while-3 example# version:1.1#! /bin/shi1sum0while((i 100))do((sumsumi))((i))doneprintftotalsum is :$sum\n#提示正常了。^M消失了。Windows下代码的换行符和Linux下的不一样导致了本例的问题。[rootoldboy scripts]# sh while.shtotalsum is :5050如果没有安装dos2unix则用下面的命令进行安装yuminstalldos2unix-y2.2、使用echo命令调试echo命令是最有用的调试脚本的工具之一。一般应在可能出现问题的脚本的重要部分加入echo命令例如在变量读取或修改操作的前后加入echo命令并紧挨着退出命令exit。范例利用echo调试一个简单的判断脚本。[rootoldboy scripts]# cat -n if-judgenum4-debug.sh1#! /bin/bash2#created by oldboy3#date:201009184#function:int compare5read-ppls input two num:a b6echo$a$b#增加打印输出确认变量值是否符合要求。7exit#退出脚本目的是不执行后面的代码。8###########9#if [ $a -lt $b ]10if(($a $b))11then12echo$a$b13elif[$a-eq$b]14then15echo$a$b16else17echo$a$b18fi执行结果如下[rootoldboy scripts]# sh if-judgenum4-debug.shpls input two num:99889988这个调试方法不是Shell的专利PHP、ASP、Perl、Python等语言都可以使用这样简单又好用的调试方法。2.3、使用bash命令参数调试除了上述的方法之外本节将讲解最重量级的方法bash或sh的参数调试方法例如[rootoldboy ]# sh [-nvx] scripts.sh参数说明如下。-n不会执行该脚本仅查询脚本语法是否有问题并给出错误提示。-v在执行脚本时先将脚本的内容输出到屏幕上然后执行脚本如果有错误也会给出错误提示。-x将执行的脚本内容及输出显示到屏幕上这是对调试很有用的参数。2.3.1、sh参数-n的测试范例通过-n参数对脚本进行语法检查。[rootoldboy ]# cat script.sh#! /bin/bashechoHello$USER, echoToday is$(date%F)[rootoldboy ]# sh -n script.sh#-n不会执行该脚本仅用于查询脚本语法是否有问题并给出错误提示。此处没有语法问题因此不显示任何信息。下面让脚本语法存在错误然后再测试这里把echoHello $USER的后半双引号去掉了。[rootoldboy ]# cat -n script.sh1#! /bin/bash2echoHello$USER#结尾少了个双引号。 3 echo Today is$(date%F)[rootoldboy ]# sh -n script.shscript.sh: line3: unexpected EOFwhilelookingformatching script.sh: line4: syntax error: unexpected end offile#上面两行报语法错误提示的内容正是第3行结尾没有双引号。2.3.2、 sh参数-v的测试范例对参数-v的测试。普通的错误脚本的执行结果如下[rootoldboy ]# sh -v script.sh#! /bin/bashechoHello$USER, echo Today is$(date%F)#以上几行是完成的脚本内容下面两行同-n的功能用于检查脚本语法。script.sh: line3: unexpected EOFwhilelookingformatching script.sh: line4: syntax error: unexpected end offile带函数的错误脚本的执行结果如下[rootoldboy ]# sh -v c.sh../function#! /bin/basholdboy(){echo I am oldboy! }oldgirl(){echo I am oldgirl }oldboy1 c.sh: line2: oldboy1:commandnot found oldgirl I am oldgirl2.3.3、sh参数-x的测试范例跟踪script.sh脚本的执行过程。[rootoldboy ]# cat script.sh#! /bin/bashechoHello$USER, echoToday is$(date%F)执行结果如下[rootoldboy ]# sh -x script.shechoHello root, Hello root, date%F echoToday is 2011-08-05Today is2011-08-05#使用-x追踪脚本是一种非常好的方法它可以在执行前列出所执行的所有程序段#如果是程序段落则在输出时最前面会加上符号表示它是程序代码#一般情况下如果是调试逻辑错误的脚本用-x的效果更佳。#缺点加载系统函数库等很多我们不想查看其整个过程的脚本时会有太多输出导致很难查看所需要的内容。利用“sh -x脚本名”调试的缺点可以用set -x命令来弥补它可以缩小调试的作用域。范例在script.sh脚本的执行过程中输出脚本的行号以便于跟踪。在一个比较长的脚本中你会看到很多的执行跟踪的输出有时候阅读起来非常费劲此时可以在每一行的前面加上内容的行号这会非常有用。要做到这样只需要设置下面的环境变量[rootoldboy ]# set|grep PS[1-5]PS1[\u\h \W]\$ PS2 PS4 #提示PS4变量在默认情况下表示加号。[rootoldboy ]# export PS4${LINENO} #此命令即可实现在跟踪过程中显示行号也可以放到脚本中。[rootoldboy ]# sh -x script.sh2echoHello root, Hello root, 3date%F 3echoToday is 2011-08-05Today is2011-08-05#提示号后面的数字就表示行号。这时可以看到bash在运行前打印出了每一行的命令。而且每行前面的号均表明了嵌套。这样的输出可以让你看到命令执行的顺序并且可以让你知道整个脚本的行为。特别说明参数-x是一个不可多得的参数在生产环境中老男孩就经常通过参数-x来实现调试的目的。一般情况下如果执行脚本发生问题非语法问题时​利用-x参数就可以知道问题出在哪一行。2.4、使用set命令调试部分脚本内容set命令也可以用于辅助脚本调试。以下是set命令常用的调试选项。set -n读命令但并不执行。set -v显示读取的所有行。set -x显示所有命令及其参数。提示通过set -x命令开启调试功能而通过set x关闭调试功能。set命令的最大优点是和bash -x相比set -x可以缩小调试的作用域。范例调试范例11-8开发的打印九九乘法表的简版脚本。[rootoldboy scripts]# cat -n for-7-9x9-2-debug.sh1#! /bin/bash2set-x#表示开启脚本调试。3forainseq94do5forbinseq96do7[$a-ge$b]echo-en$ax$b$(expr$a\ $b)8done9setx#到这里结束脚本调试即只针对sed -x和set x之间的脚本进行调试。10echo 11done执行脚本查看调试输出结果[rootoldboy scripts]# sh for-7-9x9-2-debug.shseq9forainseq 9seq9forbinseq 9[1-ge1]expr11echo-en1 x 1 1 1x11forbinseq 9[1-ge2]forbinseq 9[1-ge3]forbinseq 9[1-ge4]forbinseq 9[1-ge5]forbinseq 9[1-ge6]forbinseq 9[1-ge7]forbinseq 9[1-ge8]forbinseq 9[1-ge9]setx#可以看出跟踪脚本运行的过程但遇到set x就结束了。2x122x243x133x263x394x144x284x3124x4165x155x2105x3155x4205x5256x166x2126x3186x4246x5306x6367x177x2147x3217x4287x5357x6427x7498x188x2168x3248x4328x5408x6488x7568x8649x199x2189x3279x4369x5459x6549x7639x8729x981提示加了set -x在运行脚本的时候就不需要使用sh -x了。熟悉sh及set的用法可以让我们能够得心应手地管理Linux下Shell脚本执行的过程。在Shell脚本的学习上需要“多看、多模仿并将已有脚本修改成自己需要的样式”​这是最快的学习手段。网络上有很多实用的脚本作为初学者可以先将这些脚本拿过来将其改写为适合自己服务器的脚本然后再慢慢熟悉慢慢尝试开发新的脚本。这种先模仿后开发的学习方法会让你的学习事半功倍而且学习起来也会很有兴趣和成就感。Linux系统上本来就有很多适合阅读的规范脚本如果想要更加深入地掌握Shell脚本编程最好的方法就是阅读系统的这些脚本然后仔细研究每一行都是什么作用为什么这样写久而久之你的Shell开发水平就会得到大幅度提高。2.5、其他调试Shell脚本的工具下面再引荐两款Shell的调试工具由于老男孩已经习惯了前文讲解的调试方式因此没有过多地研究过这些调试工具如果读者有兴趣可以作为扩展知识来研究一下。1Shell调试工具bashdbShell调试器bashdb是一个类似于GDB的调试工具可以完成对Shell脚本的断点设置、单步执行、变量观察等许多功能但是老男孩很少使用它。2Shell调试工具shellcheckshellcheck是一个可检查sh/bash脚本和命令语法的小工具地址为http://www. shellcheck.net/老男孩也很少使用它。3、小结本章主要介绍了Shell的调试技巧包括1要记得首先用dos2unix对脚本从其他地方拿来用的进行格式化。2执行脚本根据报错来调试时要知道有时所报错误会不准确应多关联上下文查看。3可通过sh -x命令调试整个脚本且显示执行过程。4set -x和set x命令用于调试部分脚本的执行过程可在脚本中设置​。5可通过echo命令输出脚本中要确认的变量及相关内容然后紧跟着使用exit退出不执行后面程序这种方式便于一步步跟踪脚本对于逻辑错误的调试比较好用。写法即“echo $var; exit”6最关键的还是要语法熟练养成良好的编码习惯提高编程思想将错误扼杀在萌芽状态之中从而降低错误率减轻调试的负担提高开发效率。
返回列表