ARTICLE DETAIL

资讯详情

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

Shell编程——循环控制及状态返回值

Shell编程——循环控制及状态返回值 循环控制及状态返回值1、break、continue、exit、return的区别和对比2、break、continue、exit功能执行流程图3、break、continue、exit、return命令的基础示例4、循环控制及状态返回值的企业级案例1、break、continue、exit、return的区别和对比在上述命令中break、continue在条件语句及循环语句for、while、if等中用于控制程序的走向exit则用于终止所有语句并退出当前脚本除此之外exit还可以返回上一次程序或命令的执行状态值给当前Shell;return类似于exit只不过return仅用于在函数内部返回函数执行的状态值。关于这几个命令的基本说明如表所示。2、break、continue、exit功能执行流程图在循环中break功能的执行流程逻辑图如图所示。在循环中continue功能的执行流程逻辑图如图所示。在循环中exit功能的执行流程逻辑图如图所示。3、break、continue、exit、return命令的基础示例范例通过break命令跳出整个循环执行循环下面的其他程序。[rootoldboy scripts]# cat 12_1_1.sh#! /bin/bashif[$#-ne1];then#如果传参个数不为1则打印下面的使用提示给用户。echo$usage:$0{break|continue|exit|return}#分别传入4个命令作为参数。exit1#退出脚本。fitest(){#定义测试函数。for((i0;i5;i))doif[$i-eq3];then$;#这个地方的“$”就是接收函数外的参数将来就是{break|continue|exit|return}中的一个。fiecho$idoneechoI am in func.#循环外的输出提示。}test$#这里的“$”为函数的传参。func_ret$?#接收并测试函数返回值。if[echo$|grepreturn|wc-l-eq1]#如果传参有return。thenechoreturns exit status:$func_ret#则提示return退出状态。fiechook#函数外的输出提示。传入break命令的执行结果为[rootoldboy scripts]# sh 12_1_1.shusage:12_1_1.sh{break|continue|exit|return}[rootoldboy scripts]# sh 12_1_1.sh break012I aminfunc.#循环外的输出提示。ok#函数外的输出提示。根据结果可以看到i等于3及以后的循环没有被执行但循环外的echo执行了执行到break时跳出了if及外层的for循环语句然后执行for循环外部done后面的打印ok的语句。传入continue命令的执行结果为[rootoldboy scripts]# sh 12_1_1.sh continue012#没有3。45I aminfunc.#循环外的输出提示。ok#函数外的输出提示。可以看到只有i等于3这层循环没有被执行其他循环全部执行了循环外的echo也执行了说明执行到continue时终止了本次循环而继续下一次的循环直到循环正常结束接着继续执行了循环外面的所有语句。传入exit 119命令的执行结果为[rootoldboy scripts]# sh 12_1_1.sh exit 119012#只打印了0,1,2。[rootoldboy scripts]# echo $?119#返回了119即传入的值。根据执行结果可以看到当进入循环里的if语句后遇到exit 119时立刻退出程序不但循环体3后面的数字没有输出而且for循环体done外的echo和函数外的ok也没有输出就直接退出了程序。另外因为程序退出时指定了119所以执行脚本后获取$? 的返回值时就返回了exit 119后面的119这个数字到当前的Shell。传入return 119命令的执行结果为[rootoldboy scripts]# sh 12_1_1.sh return 119012returnsexitstatus:119#确实将119返回到了函数的外部脚本。ok[rootoldboy scripts]# echo $? #执行脚本后的返回值还是0。0根据执行结果可以看到当进入循环里的if语句后遇到return 119就没有打印3以下的数字说明return跳出了循环体程序也没有执行for循环体done外的echo命令而是直接执行了函数test外的if语句及打印ok的命令可见return的作用是退出当前函数。同时return将数字119作为函数的执行状态值返还给函数体外执行脚本后打印返回值是0因为程序的最后一行是打印ok的命令执行是成功的。4、循环控制及状态返回值的企业级案例范例开发Shell脚本实现为服务器临时配置多个IP并且可以随时撤销配置的所有IP。IP的地址范围为10.0.2.110.0.2.16其中10.0.2.10不能配置。首先给网卡配置额外的IP。以下介绍两种配置IP的命令ifconfig/ip​。使用ifconfig配置别名IP的方法ifconfigeth0:010.0.2.10/24 up#添加IP。ifconfigeth0:010.0.2.10/24 down#删除IP。使用IP配置辅助IP的方法ipaddradd10.0.2.11/24 dev eth0 label eth0:0#添加IP。ipaddr del10.0.2.11/24 dev eth0 label eth0:0#删除IP。然后批量配置IP。要求IP地址的取值范围为10.0.2.110.0.2.16其中10.0.2.10不能配置。foripin{1..16}doif[$ip-eq10]#如果变量为10即IP为10.0.2.10则调用contiune终止本次循环。thencontinue#终止本次循环。fiipaddradd10.0.2.$ip/24 dev eth0 label eth0:$ip#配置IP。done下面给出完整的脚本实现。参考答案1本答案看似很好但是实现中有不少冗余相同的代码。[rootoldboy scripts]# cat 12_2_1.sh#! /bin/sh[-f/etc/init.d/functions]./etc/init.d/functions#加载functions函数。RETVAL0add(){#配置IP函数。foripin{1..16}#列表范围为116。doif[$ip-eq10]#如果变量为10即IP为10.0.2.10则调用contiune终止本次循环。thencontinue#终止本次循环。fiipaddradd10.0.2.$ip/24 dev eth0 label eth0:$ip/dev/null#采用辅助IP形式配置IP。RETVAL$?#获取配置IP命令的返回值。if[$RETVAL-eq0]#如果返回值为0则执行then的成功提示。thenactionadd$ip/bin/true#优雅地提示成功。elseactionadd$ip/bin/false#优雅地提示失败。fidonereturn$RETVAL#获取返回值并返回给函数外的命令。}del(){#清除IP函数。foripin{16..1}#列表范围为161这里是为了删除需要不一定必须这样。doif[$ip-eq10]#如果变量为10即IP为10.0.2.10则调用contiune终止本次循环。thencontinue#终止本次循环。fi#ip addr del 10.0.2.$ip/24 dev eth0 /dev/nullifconfigeth0:$ipdown/dev/null#采用别名形式配置IP。RETVAL$?#获取配置IP命令的返回值。if[$RETVAL-eq0]#如果返回值为0则执行then的成功提示。thenactiondel$ip/bin/true#优雅地提示成功。elseactiondel$ip/bin/false#优雅地提示失败。fidone}case$1in#获取命令行的传参。start)#如果匹配start。add#则加载add函数。RETVAL$?#获取函数add执行后的返回值。;;stop)#如果匹配stop。del#则加载del函数。RETVAL$?#获取函数del执行后的返回值。;;restart)#如果匹配restart。del#则先加载del函数。sleep2#休息2秒。add#然后加载add函数。RETVAL$?#获取函数add执行的返回值。;;)#如果匹配其他任何值。printfUSAGE:$0{start|stop|restart}\n#则给出正确使用的提示这里使用了printf命令。esacexit$RETVAL#携带返回值退出脚本并将该值返给当前Shell这个不是必须的但是专业规范的表现。参考答案2将上述冗余相同的代码部分写成函数并使用以减少代码量。[rootoldboy scripts]# cat 12_2_2.sh#! /bin/sh[-f/etc/init.d/functions]./etc/init.d/functionsRETVAL0op(){#将上述add函数和del函数的内容整合为一个函数实现。if[$1del]thenlistecho{16..1}elselistecho{1..16}fiforipin$listdoif[$ip-eq10]thencontinuefiipaddr$110.0.2.$ip/24 dev eth0 label eth0:$ip/dev/nullRETVAL$?if[$RETVAL-eq0]thenaction$1$ip/bin/true#此处的提示用通用的$1传参来控制。elseaction$1$ip/bin/false#此处的提示用通用的$1传参来控制。fidonereturn$RETVAL}case$1instart)opadd#启动时就传参add给op函数。RETVAL$?;;stop)opdel#停止时就传参del给op函数。RETVAL$?;;restart)opdelsleep2opaddRETVAL$?;;)printfUSAGE:$0{start|stop|restart}\nesacexit$RETVAL范例分析Apache访问日志把日志中每行的访问字节数所对应的字段数字相加计算出总的访问量。给出实现程序请用while循环结构实现。​3分钟参考答案1:while循环采用bash exec内置命令和expr判断整数​。[rootoldboy scripts]# cat 12_3_1.sh#! /bin/bashsum0#初始化资源大小总和为0。exec$1#将传参$1输入重定向给exec。whilereadline#按行读取传参的文件内容。dosizeecho$line|awk{print $10}#获取每行的第10列即资源访问字节列。expr$size1/dev/null#数字判断。if[$?-ne0];then#如果非数字continue#则执行continue终止本次循环即不是数字的列不对其进行加法。fi((sumsumsize))#将获取到的字节做加法并赋值给sum。doneecho${1}:total:${sum}bytes echo$((${sum}/1024))KB#循环完毕后打印结果。参考答案2:while循环采用bash exec内置命令变量子串替换特殊方法来判断整数​。exec$1sum0whilereadlinedonumecho$line|awk{print $10}[-n$num-a$num${num//[^0-9]/}]||continue#若num为数字不成立则执行continue。((sumsumnum))doneecho${1}:${sum}bytes echo$((${sum}/1024))KB参考答案3execaccess_2010-12-8.logsum0whilereadlinedo[-zecho$line|awk{print $10}|seds#[0-9]##g]||continue#当双引号里的内容长度为0不成立实际上还是判断要加和的字节列是否为数字则执行continue。((sumsumecho $line|awk {print $10}))doneecho$sum范例已知下面的字符串是通过将RANDOM随机数采用md5sum加密后任意取出连续10位的结果请破解这些字符串对应的md5sum前的数字4fe8bf20ed解题思路本题原本是想考察break的用法但是还考察了RANDOM随机数的范围该范围是032767请务必记住。要想解决本题首先要将032767范围内的所有数字通过md5sum加密并把加密后的字符串和加密前的数字对应地写到日志里。然后将题中给出的加密后的字符串4fe8bf20ed和指纹库里的所有使用md5sum加密后的字符串进行比对grep最佳​如果匹配则把对应的行及对应的数字输出。解答过程如下。首先将032767范围内的所有数字通过md5sum加密并把加密后的字符串和加密前的数字对应地写到日志里实现脚本如下[rootoldboy scripts]# cat 12_4_1.sh#! /bin/bashfornin{0..32767}doechoecho$n|md5sum$n/tmp/zhiwen.log#注意加密前和加密后的对应关系。done查看执行后的结果[rootoldboy scripts]# head /tmp/zhiwen1.log897316929176464ebc9ad085f31e7284 -0b026324c6904b2a9cb4b88d6d61c81d1 -126ab0db90d72e28ad0ba1e22ee510510 -26d7fce9fee471194aa8b5b6e47267f03 -348a24b70a0b376535542b996af517398 -41dcca23355272056f04fe8bf20edfce0 -59ae0ea9e3c9c6e1b9b6252c8395efdc1 -684bc3da1b3e33a18e8d5e1bdd7a18d7a -7c30f7472766d25af1dc80b3ffc9a58c7 -87c5aba41f53293b712fd86d08ed5b36e -9...省略3万多行..然后将题中给出的加密后的字符串4fe8bf20ed和指纹库里所有使用md5sum加密后的字符串进行比对grep最佳​如果匹配则输出对应的行及对应的数字。[rootoldboy scripts]# cat 12_4_2.sh#! /bin/bash#/tmp/zhiwen.log#for n in {0..32767}#do# echo echo $n|md5sum $n /tmp/zhiwen.log#done#上述内容被注释掉了读者也可以打开注释查看。md5char4fe8bf20ed#定义待破解的字符串。whilereadline#进入循环。doif[echo$line|grep$md5char|wc-l-eq1]#循环日志中的每一行都通过grep进行过滤如果符合要求则wc后的值会等于1表示查找到了。thenecho$line#打印查找到的行。breakfidone/tmp/zhiwen.log#读取加密串的日志。执行结果如[rootoldboy scripts]# sh 12_4_2.sh1dcca23355272056f04fe8bf20edfce0 -5该4fe8bf20ed对应的md5sum加密前的随机数为数字5。
返回列表