编写shell脚本--启动一个项目


本项目是编写一个报告生成器,它会显示系统的各种统计数据和状态。并以HTML格式来产生报告。这样,我们就可以使用Web浏览器进行查看。
程序一般由一系列阶段组成,每一个阶段都会增加一些特性和功能。该程序的第一阶段是创建一个非常小的HTML页面,它不包含任何系统信息(后面会添加这些信息)。

一、第一阶段:最小文档

我们需要知道的第一件事就是一个结构良好的HTML文档的格式,如下所示。

<HTML>
		<HEAD>
				<TITLE>Page Title</TITLE>
		</HEAD>
		<BODY>
				Page body.
		</BODY>
</HTML>

如果将这些内容输入到文本编辑器,并将该文件保存为foo.html,就可以在火狐浏览器中输入file:///home/username/foo.html这个URL地址查看该文件。
程序的第一阶段时将这个HTML文件输出到标准输出。我们可以编写一个程序,来容易地完成该任务。启动文本编辑器,然后创建一个名为~/SHELL/bin/sys_info_page的新文件。

vim ~/SHELL/bin/sys_info_page

随后输入以下的程序。

#!/bin/bash

#Program to output a system information page

echo  "<HTML>"
echo "		<HEAD>"
echo "					<TITLE>Page Title</TITLE>"
echo "		</HEAD>"
echo "		<BODY>"
echo "					Page body."
echo "		</BODY>"
echo "</HTML>"

这个程序包含一个“shebang”、一条“注释”(总是一个比较好的习惯)和一系列echo命令。每一个`echo命令用来显示一行。保存该文件之后,将其成为可执行文件,并尝试去运行它。

chmod 755 ~/SHELL/bin/sys_info_page
sys_info_page

在这里插入图片描述
该程序在运行时,我们就可以看到这个HTML文档的文本显示在屏幕上,这是因为脚本中的echo命令将其输出发送到了标准输出。再一次运行该程序,并且将该程序的输出重新第你想到sys_info_page.html文件,这样就可以用Web浏览器查看结果了。

sys_info_page > sys_info_page.html
firefox sys_info_page.html

在这里插入图片描述
在编写程序时,最好尽力保持程序的清晰明了。当一个程序利于阅读和理解时,维护起来也会很容易,而且通过减少输入量,也会使得程序更容易编写。该程序的当前版本虽然工作良好,但是可以更简洁一些。实际上,我们可以敬爱嗯所有的echo命令整合为一个命令,这样就可以更容易地将更多的行添加到程序的输出中。现在,将程序修改为如下所示:

#!/bin/bash

#Program to output a system information page

echo  "<HTML>
					<HEAD>
							<TITLE>Page Title</TITLE>
					</HEAD>
					<BODY>
							Page body.
					</BODY>
</HTML>"

一个带引号的字符串可以包含换行符,因此也就可以包含多个文本行。shell将持续读取文本,直到读取到下一个引号为止。它在命令行中也是这样工作的:

[wangjichuan@Jarvis ~]$ echo "<HTML>
>					<HEAD>
>							<TITLE>Page Title</TITLE>
>					</HEAD>
>					<BODY>
>							Page body.
>					</BODY>
>  </HTML>"

每行开头的>字符时包含在PS2 shell变量中的shell提示符。每当我们在shell中输入多行语句时就会出现。

二、第二阶段:加入一点数据

现在该程序可以生成一个最小的文档,我们在这个文档中加入一些数据。
为了实现这个目标,需要做以下改动。

#!/bin/bash

#Program to output a system information page

echo  "<HTML>
					<HEAD>
							<TITLE>System Information Report</TITLE>
					</HEAD>
					<BODY>
							<H1>System Information Report</H1>
					</BODY>
</HTML>"

我们加入了一个页面标题,并为报告正文部分添加了一个标题。

三、变量和常量

但是,脚本现在还有一个问题。请注意字符串“System Information Report”是如何被重复的。对于我们这个小脚本来说,这不是问题。但是,如果我们的脚本很长,而且多处存在该字符串,现在我们向将标题修改为其他内容,则需要在多个地方进行修改,这样工作量就大了。我们是否可以修改脚本,使得字符串只出现一次而不是多次呢?而且这也会让脚本在日后的维护更加简单。为此,可以这样做:

#!/bin/bash

#Program to output a system information page

title="System Information Report"

echo  "<HTML>
					<HEAD>
							<TITLE>$title</TITLE>
					</HEAD>
					<BODY>
							<H1>$title</H1>
					</BODY>
</HTML>"

通过创建一个名为title的变量,并且将其赋值为"System Information Report",就可以利用参数扩展,将该字符串放置到多个地方了。

3.1、创建变量和常量

如何创建变量呢?这很简单,我们刚刚使用过。当shell遇到一个变量时,会自动创建这个变量。这点与大多数程序中,使用一个变量必须先声明或定义有所不同。在这个方面,shell非常的宽松,但也会导致一些问题。例如,请看以下命令行中出现的场景;

[wangjichuan@Jarvis ~]$ foo="yes"
[wangjichuan@Jarvis ~]$ echo $foo
yes
[wangjichuan@Jarvis ~]$ echo $foo1
[wangjichuan@Jarvis ~]$

首先我们为变量foo赋值为yes,再使用echo命令显示foo的值。然后我们显示一个由拼写错误造成的变量foo1的值,而得到一个空值。这是因为shell在遇到foo1变量时,会轻松地创建这个变量,并且为这个foo1变量赋了一个默认的空值。从这点可以看出,我们必须对拼写有足够的关注。同时,我们也要理解在这个示例中,究竟发生了什么。

[wangjichuan@Jarvis ~]$ echo foo

会经历参数扩展,而且结果是:

[wangjichuan@Jarvis ~]$ echo yes

然而命令

[wangjichuan@Jarvis ~]$ echo foo1

则扩展为

[wangjichuan@Jarvis ~]$ echo 

这个为空的变量在扩展后为空。这对需要使用参数的命令来说,将会引起混乱。例如:

[wangjichuan@Jarvis ~]$ foo=foo.txt
[wangjichuan@Jarvis ~]$ foo1=foo1.txt
[wangjichuan@Jarvis ~]$ cp $foo $foo1
cp: missing destination file operand after 'foo.txt'
Try 'cp  --help' for more information.

我们为变量foo和foo1赋值,然后执行cp命令,但将第二个参数名拼错了。在参数扩展后,这个cp命令仅接受了一个参数,但是它需要的是两个。


变量的命名规则如下所示:

  • 变量名称应有字母、数字和下划线组成。
  • 变量名称的第一个字符必须是字母或下划线。
  • 变量名称中不允许空格和标点。

变量意味着值会发生变化,并且在大多数应用中,变量就是这样使用的。在前面的应用中,变量title其实是作为常量使用的。常量其实就是u一个有名称和确定值的变量。区别就是,常量的值不会发生变化。在一个执行几何计算的应用中,我们可以定义PI为一个常量,并且将它的值赋为3.1415,从而无需在程序中使用数值3.1415。对于shell来说,变量和常量没有区别,这种划分更多的是为了编程者的方便。较为普遍的约定是,我们使用大写字母表示常量,使用小写字母表示变量。我们将前面的shell按照这个约定进行修改。

#!/bin/bash

#Program to output a system information page

TITLE="System Information Report For $HOSTNAME"

echo  "<HTML>
					<HEAD>
							<TITLE>$TITLE</TITLE>
					</HEAD>
					<BODY>
							<H1>$TITLE</H1>
					</BODY>
</HTML>"

我们为shell中的变量HOSTNAME赋值。这个HOSTNAME是机器在网络上的名称。

注意:实际上,shell还提供了了强制常量不发生变化的方法,这是通过使用带有-r选项(只读)的delcare内置命令实现的。我们在这里使用这种方式为变量TITLE赋值:delcare -r TITLE="Page Title",shell将阻止一切后续的向TITLE的赋值。这个特性很少使用,但在很早的脚本中曾经存在。

3.2、为变量和常量赋值

这是我们开始真正使用扩展的地方。我们已经看到,变量用以下方式进行赋值:variable = value
其中,variable是变量的名称,value是变量的值。和大多数编程语言不同,shell并不关心赋给变量的值的数值类型,它会将其都当成字符串。通过使用带-i选项的delcare命令,可以强制shell将变量限制为整形数值。但是,这如同将变量设置成只读模式一样,我们很少这样做。
注意,在赋值时,变量名、等号和值之间不能含有空格。那么,变量的值中可以包括什么呢?它包含的时可以扩展为字符串的任意值:

a=z                                       #将字符串“z”赋值给变量a
b="a string"                     #嵌入的空格必须用引号括起来
c="a string and $b"      #可以被扩展到赋值语句中的其他扩展,比如变量
d=$(ls -l foo.txt)             #命令的结果
e=$((5*7))                         #算术扩展
f="\t\ta string\n"           #转义序列,比如制表符和换行符

可以在一行中给多个变量赋值。

a==5  b="a  string"

在扩展期间,变量名称可以用花括号“{}”括起来。当变量名因为周围的上下文而变得不明确时,这就会很有帮助。在这里,我们使用变量将一个文件的名字由myfile改为myfile1:

[wangjichuan@Jarvis ~]$ filename="myfile"
[wangjichuan@Jarvis ~]$ touch $filename
[wangjichuan@Jarvis ~]$ mv $filename $filename1
mv: missing destination file operand after 'myfile'
Try 'mv  --help' for more information.

因为shell将mv命令的第二个参数当成了一个新的变量,所以这样做没有成功。该问题可以用以下方法解决。

[wangjichuan@Jarvis ~]$ mv $filename ${filename}1

用花括号括起来,shell将不会把跟在后面的“1”认为是变量名称的一部分。
我们现在添加一些数据到我们的报告中,比如报告创建的日期、时间,以及报告创建者的用户名。

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

echo  "<HTML>
					<HEAD>
							<TITLE>$TITLE</TITLE>
					</HEAD>
					<BODY>
							<H1>$TITLE</H1>
							<P>$TIME_STAMP</P>
					</BODY>
</HTML>"

在这里插入图片描述

四、here文档

我们已经了解了两种通过echo命令输出文本的不同方法。此外还有称之为“hure文档”或“here文档”的第三种方法来输出文本。here文档是I/O重定向的另外一种形式,我们在脚本中嵌入正文文本,然后将其输入到一个命令的标准输入中。工作方式如下:

command << token
text
token

其中,command是接受标准输入的命令名,token是用来指示嵌入文本结尾的字符串。现在修改脚本,使其使用here文档。

#!/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>
					</BODY>
</HTML>
_EOF_

我们的脚本不再使用echo,而是使用cat和here文档。字符串_EOF_(含义是文件结尾)被选做token,并且指示嵌入文本的结尾。注意,token必须在一行和宗单独出现,而且文本行的末尾没有空格。
那么使用here文档有什么好处呢?它和echo命令很类似,但是在默认情况下,here文档内的单引号和双引号将失去他们在shell中的特殊含义。下面是一个命令行示例。
在这里插入图片描述
可以看到,shell没有注意到引号,而是将引号当作普通字符。这就可以在here文档中随意嵌入引号。这给我们的报告程序到来了方便。
here文档可以和能够接受标准输入的任何命令一起使用。在本例中,我们使用here文档向ftp程序传递一系列命令,以从远程FTP服务器获取一个文件。

#!/bin/bash

# Script to retrieve a file via FTP

FTP_SERVER=ftp.n1.debian.org
FTP_PATH=/debian/dists/lenny/main/installer-i386/current/images/cdrom
REMOTE_FILE=debian-cd_info.tar.gz

ftp -n << _EOF_
open $FTP_SERVER
user anonymous me@linuxbox
cd $FTP_PATH
hash
get $REMOTE_FILE
bye
_EOF_
ls -l $REMOTE_FILE

如果将重定向操作符由“<<”改为"<<-",shell就会忽略在here文档中开图的Tab字符。这样就能缩进here文档,从而提供可读性。

#!/bin/bash

# Script to retrieve a file via FTP

FTP_SERVER=ftp.n1.debian.org
FTP_PATH=/debian/dists/lenny/main/installer-i386/current/images/cdrom
REMOTE_FILE=debian-cd_info.tar.gz

ftp -n <<- _EOF_
				open $FTP_SERVER
				user anonymous me@linuxbox
				cd $FTP_PATH
				hash
				get $REMOTE_FILE
				bye
				_EOF_
ls -l $REMOTE_FILE
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读