编写shell脚本--自顶向下设计

一、shell函数

我们的报告当前执行如下步骤,即可生成HTML文档。

  1. 打开页面
  2. 打开页面标题
  3. 设置页面标题
  4. 关闭页面标题
  5. 打开页面主体
  6. 输出页面主体
  7. 输出时间戳
  8. 关闭页面主体
  9. 关闭页面

为了下一阶段的开发,我们将在步骤7和步骤8之间额外添加一些任务,如下所示。

  • 系统正常运行时间和负载。这是自上次关机或重启之后系统的运行时间,在几个时间间隔内,当前运行在处理器上的平均任务量。
  • 磁盘空间。系统存储空间的使用情况。
  • 用户空间。每个用户所使用的存储空间。

在这些任务中,如果每个任务都有一条对应的命令,我们可以直接通过命令替换的方式,将它们添加到脚本中。

#!/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"

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_

我们可以通过两种方式创建这些额外的命令。我们可以编写3个独立的脚本,并把它们放置到环境变量PATH所列出的目录中,或者是我们可以将脚本作为shell函数嵌入到程序i中。shell函数是位于其他脚本中的迷你脚本,可以用作自主程序(autonomous program)。shell函数由两种语法形式。第一种如下所示:

function name {
		commands
		return
}

其中name是指示这个函数的名称,commands是这个函数中的一系列命令。第二种看起来如下所示:

name() {
		commands
		return
}

这两种格式等价,并且可以交替使用。来看下面这个脚本,它演示了shell函数的使用。

#!/bin/bash

#shell function demo

function funct {
		echo "Step 2"
		return
}

#Main program starts here

echo  "Step 1"
funct
echo  "Step 3"

当shell读取脚本的时候,它会跳过1~11行,这些行包含的是注释和函数的定义。执行从带有echo命令的第12行开始。第13行调用了shell函数funct,shell会执行这个函数,而且其执行方式与执行其他命令时相同。程序控制权然后移动到第6行,执行第二个echo命令,随后再执行第7行。这个return命令终止函数的执行,然后将控制权汉给函数调用后面的代码(第14行),然后执行最后一个echo命令。

注意:为了让函数调用被识别为shell函数,而不是被解释为外部程序的名字,shell函数的定义在脚本中的位置必须在它被调用的前面。

我们在脚本中添加上最小的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 () {
	return
}
report_disk_space () {
	return
}
report_home_space () {
	return
}
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函数的命令规则和变量相同。一个函数必须至少包含一条命令。return命令(可选的)可以满足该要求。

二、局部变量

在目前我们所编写的脚本中,所有的变量(包括常量)都是全局变量。全局变量在整个程序期间会一直存在。在很多情况下,这很不错。但是有时候,它会让shell函数的使用变得复杂。在shell函数中,经常需要的是局部变量。局部变量仅仅在定义他们的shell函数中有效,一旦shell函数终止,它们就不再存在。
局部变量可以让程序员使用已经存在的变量名称,无论是脚本中的全局变量,还是其他shell函数中的变量,而不用考虑潜在的命名冲突。
下面是一个显示如何定义和使用局部变量的脚本示例。

#!/bin/bash

#local-vars: script to demonstrate local variables

foo=0  #global variable foo

funct_1 () {
	local foo # variable foo local to funct_1
	foo=1
	echo "funct_1:  foo=$foo"
}
funct_2 () {
	local foo # variable foo local to funct_2
	foo=2
	echo "funct_2: foo=$foo"
}

echo "global: foo = $foo"
funct_1
echo "global: foo = $foo"
funct_2
echo "global: foo = $foo"

可以看到,局部变量是通过在变量名前面添加单词local来定义的。这样,就创建并同时定义了一个shell函数中的局部变量。一旦出了这个shell函数,这个局部变量将不再存在。当运行脚步时,结果如下所示:

[wangjichuan@Jarvis ~]$ local-vars
global: foo = 0
funct_1: foo=1
global: foo = 0
funct_2: foo=2
global: foo = 0

可以看到,在两个shell函数中对局部变量foo的赋值,不影响shell函数以外定义的变量foo的值。
这个特性可以让我们编写的shell函数相互独立,而且也独立于它们所在的脚本。这非常有用,因为它有助于阻止程序中各个部分的相互干扰。该特性也可以让我们编写出可移植的shell函数。也就是说,我们可以根据需要将某一脚本中的shell函数剪切下来,然后粘贴到另外一个脚本中。

三、保持脚本的运行

在开发程序时,让程序保持可运行的状态会非常有用。通过这种方式,并经常测试,就可以在开发过程的早期检测到错误。这也会让问题的调试变得容易。例如,如果我们运行某个程序,并对它做了细微的改动,然后再次运行该程序,此时发现了问题。这可能时最近的改动导致的。通过添加空函数(程序员将其成为stub),我们可以在早期验证程序的逻辑流程。当构建一个stub时,最好时包含一些能够为程序员提供反馈信息的东西,这些反馈信息可以显示正在执行的逻辑流程。

report_uptime () {
	cat <<- _EOF_
					<H2>System Uptime</H2>
					<PRE>$(UPTIME)</PRE>
					_EOF_
	return
}

该函数的代码直接了当。我们使用了一个here文档来输出一个标题,并输出uptime命令的结果。命令结果使用

标签围起来,其目的是保留命令的格式。report_disk_space函数也类似。

report_disk_space () {
	cat <<- _EOF_
					<H2>Disk Space Utilization</H2>
					<PRE>$(df -h)</PRE>
					_EOF_
	return
}

这个函数使用了df -h这个命令来检查磁盘的空间。随后,我们来构建report_home_space函数。

report_home_space () {
	cat <<- _EOF_
					<H2>Home Space Utilization</H2>
					<PRE>$(du -sh /home/*)</PRE>
					_EOF_
	return
}

我们使用带-sh选项的du命令来执行这个任务。这个并不是问题的完整解决方案。虽然可以在某些操作系统中(例如Ubuntu)运行,但是在其他系统中则无效。这是因为很多系统设置了主目录的权限,以防止被其他用户读取,这种安全措施也很合理。在这些操作系统中,只有在超级用户运行我们的脚本时,我们编写的这个report_home_space函数才会执行。一个更好的解决方案是让脚本根据用户的权限调整自己的行为。
在这里插入图片描述

你的.bashrc文件中的shell函数

shell函数可以很好的取代别名,并且实际上也是创建个人使用的小命令的首选方法。别名非常局限于命令的种类和它们所支持的shell特性,而shell特性则允许任何可以编写为脚本的东西。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章