十年运维系列之基础篇 - Linux
作者:曾林
联系:[email protected]
版权:文章未经同意请勿转载
一、引言
随着程序越来越大,越来越复杂,设计、编码和维护都将越来越困难。所以,在设计任何大型项目的时候,我们最好将庞大的、复杂的任务,拆分成一系列小的、简单的任务。
想象一下,我们来描述一个常见的日常任务:你去超市买东西。我们可以按照如下的步骤来进行。
- 选择商品
- 结账
- 离开
但是,我们在结账这个环节则可能需要更多的细节。我们来继续将“结账”这个步骤进一步拆分为一系列的步骤。
- 排队
- 统计商品
- 付钱
- 收取零钱
这种先确定上层步骤,然后再逐步细化这些步骤的过程,称之为自顶向下的设计。
通过这种设计方式,我们可以将大而且复杂的任务分解成很多小而简单的任务。自顶向下设计是一种设计程序的常见方式,尤其适合shell编程。
二、shell函数
所谓shell函数,本质上就是shell脚本中的迷你脚本。shell函数有两种语法形式。第一种如下所示:
function name { commands return }
其中name是指这个函数的名称,commands是这个函数中的一系列命令。第二种看起来如下所示:
name() { commands return }
这两种形式等价,并且可以交替使用。如下,我们来提供一个简单的脚本来展示一下shell函数的使用。
#!/bin/bash # Program to output a system information page TITLE="System Information Report for $HOSTNAME" CURRENT_TIME=$(date +"%x %r %Z") TIME_STAMP="Generated $CURRENT_TIME, by $USER" report_uptime() { cat <<- _EOF_ <H2>Report Uptime</H2> <PRE>$(uptime)</PRE> _EOF_ } report_disk_space() { cat <<- _EOF_ <H2>Report disk space</H2> <PRE>$(df -h)</PRE> _EOF_ } report_home_space() { cat <<- _EOF_ <H2>Report home space</H2> <PRE>$(du -sh /home/*)</PRE> _EOF_ } cat << _EOF_<HTML> <HEAD> <TITLE>$TITLE</TITLE> </HEAD> <BODY> <H1>$TITLE</H1> <P>$TIME_STAMP<P> $(report_uptime) $(report_disk_space) $(report_home_space) </BODY></HTML>_EOF_
三、局部变量
在目前我们所编写的脚本中,所有的变量(包括常量)都是全局变量。全局变量在整个程序期间会一直存在。在很多情况下,这都不错。但是有时候,它会让shell函数的使用变得复杂。在shell函数中,经常需要的是局部变量。局部变量仅仅在定义它们的shell函数中有效,一旦shell函数终止,它们就不会存在。
局部变量可以让程序员使用已经存在的变量名称,无论是脚本中的全局变量,还是其他shell函数中的变量,而不用考虑潜在的命名冲突。
下面定义一个显示如何定义和使用局部变量的脚本示例。
1 #!/bin/bash 2 3 # local-vars: script to demenstrate local variables 4 5 foo=0 # global variable foo 6 7 funct_1() { 8 local foo 9 foo=1 10 echo "funct_1: foo = $foo" 11 } 12 13 funct_2() { 14 local foo 15 foo=2 16 echo "funct_2: foo = $foo" 17 } 18 19 echo "global: foo = $foo" 20 funct_1 21 echo "global: foo = $foo" 22 funct_2 23 echo "global: foo = $foo"
运行结果如下图:
可以看到,局部变量是通过在变量名前面添加单词local来定义的。这样,就创建并同时定义了一个shell函数中的局部变量。一旦出了这个shell函数,这个局部变量将不再存在。因此,在两个shell函数中对局部变量foo的赋值,不影响shell函数以外定义的变量foo的值。
四、保持脚本的运行
在开发程序的时候,让程序保持可运行的状态会非常有用。通过这种方式,并经常测试,就可以在开发过程的早期检测到错误。这也会让问题的调试变得容易。例如,如果我们运行某个程序,并对它做了细微的改动,然后再次运行该程序,此时发生了问题。这可能是有可能最近的改动所造成的。通过添加空函数(程序员称之为stub),我们可以在早期验证程序的逻辑流程。当构建一个stub时,最好是包含一些能够为程序员提供反馈信息的东西,这些反馈信息可以显示正在执行的逻辑流程。
五、在.bashrc中添加shell函数
shell函数可以很好的取代别名,并且实际上也是创建个人使用的小命令的首选方法。别名非常局限于命令的种类和它们支持的shell特性,而shell特性则允许任何可以编写为脚本的东西。例如,如果我们很喜欢为脚本开发report_disk_space这个shell函数,则可以为.bashrc文件创建一个相似的名为ds的函数。
ds() { echo "Disk Space Utilization for $HOSTNAME" df -h }
六、本章结束语
在本章,我们介绍了一种常用的程序设计方法——自顶向下,并知道了如何使用shell函数按照要求来构建逐步细化的任务。我们还学习了如何使用局部变量时shell函数的相互独立,并独立于它们所在的程序。这样,我们就可以以可移植和可重用的方式编写shell函数,并将其用到多个程序中,从而节省大量的时间。