一个coding小技巧
今天写autogeili脚本时遇到一个问题,每次命令执行后都要判断命令执行的情况,如果没有成功执行,那么脚本就要终止,不能继续向下做。只有上一步成功完成,才能执行接下来的步骤。很容易联想到以下逻辑:
执行命令1
判断命令正确执行?
是:跳转到命令2
否:输出错误信息并终止脚本执行
执行命令2
判断命令正确执行?
是:跳转到命令3
否:输出错误信息并终止脚本执行
……
执行命令n
判断命令正确执行?
是:跳转到命令n+1
否:输出错误信息并终止脚本执行
这实在是很让人抓狂的一大堆exit或者return~~这时我想起了一本很著名的书中提到的一个方法,这本书已经著名到我把名字忘掉了~~巧用while false循环来解决掉这些恼人的随时可能结束的分支,让程序更加结构化。
说到使用while false循环,不得不提到while true循环,也就是常说的死循环。死循环是在程序中不能够出现的,一旦出现,你只能祈祷用户知道Ctrl+C这个组合键了。不过有一类“死循环”却每时每刻都为我们服务,那就是消息处理时的死循环,像gtk框架中的gtk_main()其实就是启动一个死循环。当然这个死循环会在一些特定函数被调用时退出,我喜欢叫它“受控制的死循环”,因为毕竟它还是能够退出的,而不是强制使用Ctrl+C这个组合键。
如果while true是“可控制”的,那么while true还有可能从逻辑上被人们接受。不过while false就没那么容易让人接受了,请看如下逻辑:
while false
do
something you want to do
done
这很明显是个程序员用来戏弄编译器而写出的代码,因为无论do~done块中写些什么,编译器都会毫不留情的将这部分代码优化掉,因为他们根本不会被执行。不过如果我们调整一下while语句的位置,情况就大不同了:
do
something you want to do
done
while false
这里很明显可以看出,do~done块中的语句只可以被执行一次。“那为什么还要while循环?直接写这些语句就是这个效果啊!”其实想达到我们省略掉一堆return和exit的目的,还需要一个语句来帮忙,那就是break,现在也许你刚才的疑问已经可以找到答案了。请看完整版:
do
command1
if (command1 failed) break
command2
if (command2 failed) break
……
command n
if (command n failed) break
all commands ransuccessfully!
return 0
done
while false
some commandsfailed
return -1
这个结构是不是让你很满意呢?我觉得至少比刚才好多了~~
Bash中的问题
bash在while循环的支持上,没有提供将while写在do~done块后面的语法支持,所以不能直接用上述的coding技巧,我做了一点小变通,也能顺利完成任务:
while true
do
command1
if (command1 failed) break
command2
if (command2 failed) break
……
command n
if (command n failed) break
all commands ransuccessfully!
return 0
done
some commandsfailed
return -1
其实如果可以直接写return的话,这种变通也是可以不用的。如果后续还有别的工作,记得在done前加上一个无条件的break,就可以保证代码执行一次了。因为我们只是想利用break在循环中的特点,而不是真正需要一个循环。