楼主: bnso

Linux Shell介绍

[复制链接]
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
171#
 楼主| 发表于 2006-8-13 19:26 | 只看该作者
第27章几个脚本例子
本章包含了我最常用的几个脚本。你会发现它们都相当短小而简单。这就是脚本的一个优
点;它不是很长、很复杂,只需很短的代码就能够完成相当多的功能,可以节约大量的时间。
本章中包含以下内容:
• 各种脚本的例子。
我本来打算在本章中提供一个通用的数据验证数据库脚本,但是由于它超过了5 0 0行,我
觉得编辑肯定不会同意把它收入书中。那个脚本几年前只有几行,后来由于不断增加功能,
变成了现在这么长。最后,我选择了如下六个脚本作为例子:
p i n g a l l:一个按照/ e t c / h o s t s文件中的条目逐一p i n g所有主机的脚本。
b a c k u p _ g e n:一个通用的备份脚本,能够加载缺省设置。
d e l . l i n e s:一个引用s e d命令的脚本,能从文件中删除若干行。
a c c e s s _ d e n y:一个能够阻止某些特定用户登录的工具。
l o g r o l l:一个能够清除超过某一长度的日志的工具。
n f s d o w n:一个快速u n m o u n t所有n f s文件系统的工具。
27.1 pingall
几年前我写了一个名为p i n g a l l的脚本在夜间运行,把它作为常规报告脚本的一部分。它
能够按照/ e t c / h o s t s文件中的条目逐一p i n g所有的主机。
该脚本列出/ e t c / h o s t s文件并查找其中的非注释行(不以#开头的行)。然后使用一个w h i l e
循环读入所有的行,接下来使用a w k分析出每行的第一个域,并把它赋给变量A D D R。最后使
用f o r循环逐一p i n g相应的地址。
下面就是该脚本。
上述脚本可以很容易地进行扩展,加进其他网络报告工具。
27.2 backup_gen
在本章中我选择了这个脚本并不是因为它展示了如何备份目录,而是因为它是一个同其
他脚本共享设置的很好例子。
b a c k u p _ g e n是一个用于备份的脚本,它从一个缺省的配置文件中读入设置,然后根据这
些参数对系统进行备份。用户可以根据自己的需要改变这些缺省设置。这是一个不同脚本如
何使用相同设置或仅在自己运行期间改变相应设置的极好例子。当该脚本执行时,它首先确
认源文件b a c k u p . d e f a u l t s是否存在,如果不存在,则退出。
该脚本在运行时,会显示出一个题头和缺省设置,并询问用户是否需要改变任何缺省设
置。如果用户回答“是”,在他们修改设置之前,该脚本就会提示他们输入一个代码,用户可
以有三次机会;如果输入正确的代码后仍无法改变设置,这就意味着用户必须要使用缺省设
置。一般来说,在输入正确代码后,用户可以改变下列设置( [ ]中的为缺省设置):
• 磁带设备[ r m t 0 ] 可以选择r m t 1和r m t 3
• 备份完成后是否向系统管理员发邮件[是] 可以选择否
• 备份的类型[全备份] 可以选择普通备份或s y b a s e备份
脚本中使用了一些临时变量来保存被修改的设置。用户可以按回车键选择缺省设置。下
列设置不能被改变:
备份日志文件名。
用户代码。
接着所有的改变会生效。在这些改变生效之后,相应的临时变量又会被重新赋予缺省值。
在备份进行之前,首先要测试磁带设备。备份过程使用f i n d和c p i o命令,它们从设置文件中读
入相应变量的缺省值,或使用用户设定的值。
下面就是该脚本。
第27章几个脚本例子307
下载
308 第五部分高级s h e l l编程技巧
下载
第27章几个脚本例子309
下载
源文件backup.defaults中包含函数continue_prompt,还有所有缺省设置。下面就是该源文件。
310 第五部分高级s h e l l编程技巧
下载
下面是该脚本运行时的输出,缺省设置被显示在屏幕上,用户被询问是否要改变这些设
置:
第27章几个脚本例子311
下载
下面是用户改变缺省值的过程。在下面的例子中,备份类型被用户改变,但是该脚本在
检查了相应的磁带设备之后,发现它有点问题。在使用了最后一个状态命令之后,该脚本将
会退出。
27.3 del.lines
之所以要编写这个脚本,是因为应用程序开发者总是问我“用s e d的哪个命令删除空行?”。
我决定写一个小脚本给他们使用,以免他们老是打电话问我这个命令。
这个脚本只是包装了一下s e d命令,但它能够使用户很方便地使用,他们非常喜欢用。
脚本一般都不长。如果你认为写一个脚本能够使某些任务自动化,能够节约时间,那么
你就可以编写一个脚本。
这个脚本可以处理一个或多个文件。每个文件在用s e d删除空行之前要先核实是否存在。
s e d的输出被导入一个文件名中含有$ $的临时文件,最后这个临时文件又被移回到原来的文件
中。
该脚本使用s h i f t命令取得所有的文件名,用w h i l e循环逐个处理所有的文件,直至处理完
为止。
可以使用del.lines -help获得一个简短的帮助。你也可以创建一个更好的帮助。
下面是该脚本。
312 第五部分高级s h e l l编程技巧
下载
27.4 access.deny
在对系统进行某些更新时,你可能不希望用户登录,这时可以使用/ e t c / n o l o g i n文件,大
多数系统都提供这个文件。一旦在/ e t c目录中使用t o u c h命令创建了一个名为n o l o g i n的文件,
除r o o t以外的任何用户都将无法登录。
如果系统不支持这种方法,你一样还可以做到这点—可以自己创建这个文件,下面就是
具体的做法。
可以在/ e t c / p r o f i l e文件中加入下面的代码:
现在,可以通过在/ e t c目录下创建n o l o g i n文件来阻止除根用户以外的其他用户登录。记住,
该文件要对所有用户可读。
第27章几个脚本例子313
下载
当决定恢复用户登录时,只要删除该文件即可。
rm /etc/nologin
上述办法可以很方便地组织除根用户外的所有用户登录。如果希望临时禁止某个用户登
录,可以修改/ e t c / p a s s w d文件,把该用户的口令域的第一个字符变成*。不过,这个问题比较
复杂,在操作之前一定要搞清楚,否则会带来系统性的问题。
L I N U X提供了一个工具,可以通过它在l o g i n . a c c e s s文件中写入用户名和用户组。该文件
可以用来允许或禁止用户对系统的访问。
这里有一个上述工具的简化版本d e n y. a c c e s s。该脚本从/ e t c / p r o f i l e文件中运行,它读入一
个名为l o c k o u t . u s e r s的文件。该文件包含有禁止登录的用户名。如果该文件中出现了a l l这个单
词,那么除r o o t以外的所有用户都将被禁止登录。
下面是l o c k o u t . u s e r s文件的一个例子,该文件可以包含注释行。
下面解释该脚本的工作过程。首先,通过设置t r a p忽略所有的信号,这样用户就无法中断它
的执行。如果文件l o c k o u t . u s e r s存在,那么脚本将会继续运行。它首先检查该文件中是否存在单
词a l l,如果存在,就不再检查该文件中的其他用户名,并禁止除根用户以外的所有其他用户登
录。不要使用注释来屏蔽单词a l l,因为这样它仍然有可能起作用。不过你可以注释用户名。
如果单词a l l被找到,那么除r o o t外的所有用户都将无法登录。为了准确起见,在该脚本中
使用了g r e p的精确匹配模式a l l \ >。这时用户将会在屏幕上看到系统不可用的消息。
该脚本中的主要函数是get_users 。它读入文件l o c k o u t . u s e r s,忽略所有以#开头的注释行。
它通过比较用户名来确保用户名r o o t没有出现在该文件中,即使出现也不会禁止r o o t登录,否
则后果将难以想象。
当前正在登录的用户名可以从变量L O G N A M E中得到,并与变量N A M E S做比较,而变量
N A M E S的内容来自于l o c k o u t . u s e r s文件。如果匹配,相应用户的登录进程将被终止。
我在几个拥有近4 0个用户的系统上运行该脚本,它并没有影响用户登录的速度。当用户
外出超过一周或者用户午餐,而我需要对系统进行更新时,我就使用该脚本临时锁住相应的
帐户。
需要在/ e t c / p r o f i l e文件中加入这样一行。我把它加在该文件的末尾,这样即使用户无法登
录,也可以在此之前看见当前发给他的新消息。
. /apps/bin/deny.access
/ a p p s / b i n目录是我存放全局性脚本的地方—你可能把这些脚本放在另外的目录中,不过
314 第五部分高级s h e l l编程技巧
下载
一定要确保所有用户都对该脚本及存放它的目录具有执行权限。
如果得到“权限不足”的错误提示,那说明该脚本或目录的权限不足。
我的l o c k o u t . u s e r s文件放在/ a p p s / e t c目录下。如果你的系统的目录结构有所不同的话,应
该作出相应的调整。由于该文件在登录时被引用,可以使用s e t命令看到相应的函数(不过无
法看到l o c k o u t . u s e r s文件)。如果你觉得这不妥,只要在这些函数执行后使用u n s e t命令去掉它
们即可。可以把u n s e t命令直接放在/ e t c / p r o f i l e文件中该命令行之后,就像这样:
unset getusers
下面就是该脚本。
第27章几个脚本例子315
下载
27.5 logroll
我的系统中的有些日志文件增长十分迅速,每天手工检查这些日志文件的长度并倒换这
些日志文件(通常是给文件名加个时间戳)是非常乏味的。于是我决定编写一个脚本来自动
完成这项工作。该脚本将提交给c r o n进程来运行,如果某个日志文件超过了特定的长度,那
么它的内容将被倒换到另一个文件中,并清除原有文件中的内容。
你可以很容易地改编这个脚本用于清除其他的日志文件。我使用另外一个脚本来清除我的
系统日志文件,它每周运行一次,截断相应的日志文件。如果我需要再回头看这些日志文件,
只需在备份中寻找即可,这些日志文件的备份周期为1 6周,这个周期长度应该说是足够了。
该脚本中日志文件的长度限制是由变量B L O C K _ L I M I T设定的。这一数字代表了块数目,
在本例中是8块(每块大小为4 K字节)。可以按照自己的需求把这一数字设得更高。所有我要
检查的日志文件名都保存在变量L O G S中。
这里使用了一个f o r循环来依次检查每一个日志文件,使用d u命令来获取日志文件长度。
如果相应的文件长度大于B L O C K _ L I M I T变量所规定的值,那么该文件将被拷贝到一个文件
名含有时间戳的文件中,并改变这个文件所属的组,原先的文件长度将被截断为0。
该脚本由c r o n每周运行几次,生成了一些文件名中含有时间戳的日志文件备份,这样如
果系统出现了任何问题,我还可以回到这些备份中查找。
316 第五部分高级s h e l l编程技巧
下载
27.6 nfsdown
如果系统中包含n f s文件系统,你将发现下面的脚本非常实用。我管理着几台主机,不时
地需要在工作时间重启动其中的某台机器。这种重启动过程当然是越快越好。
由于我在好几个机器上都挂接了远程目录,我不想依靠系统的重启动过程来卸载这些n f s
文件系统,宁愿自己来完成这个工作。这样还可以更快一些。
只要运行这个脚本就可以迅速卸载所有的n f s文件系统,这样就能更快的重新启动机器。
该脚本的L I S T变量中含有提供n f s目录的主机名。使用f o r循环逐一卸载相应的目录,用
g r e p命令在d f命令的结果中查找n f s文件系统。n f s目录的m o u n t形式为:
machine: remote_directory
这一字符串被保存在变量N F S _ M A C H I N E中。在u m o u n t命令中使用了该变量。
下面就是该脚本:
27.7 小结
本章中所提供的脚本都是我最常用的。正如前面所提到的,脚本不一定很长、很复杂,
但是它却不失为一种高效的方法。

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
172#
 楼主| 发表于 2006-8-13 19:26 | 只看该作者
第28章运行级别脚本
如果希望在系统启动时自动运行某些应用程序、服务或脚本,或者在系统重启动时能够
正确地关闭这些程序,那么需要创建运行级别脚本。除一种L I N U X变体外,所有的L I N U X版
本都含有这种基于系统V的运行级别配置目录,就像其他U N I X版本那样。
既然所有的系统都含有这种类型的配置,我们在本章中将会对它加以介绍,但如果你的
系统不含有这种目录,也不要紧。还可以通过其他方法在系统启动时自动运行程序;本章的
后半部分也将介绍这些方法。
本章包含下列内容:
• 运行级别。
• 如何创建r c . s c r i p t s。
• 如何在不同的运行级别实现相应的r c . s c r i p t s。
• 如何从i n i t t a b中启动应用程序。
能够创建运行级别脚本就意味着能够更灵活地控制系统。如果需要在某一个特定的运行
级别启动或停止程序,就得创建运行级别脚本(它们通常被称为r c . s c r i p t)。
任何用关键字s t a r t或s t o p调用的、能够启动或停止程序运行的脚本都可以看作是一个
r c . s c r i p t。注意,应当由用户来保证他或她所提交的脚本是一个有效的脚本,能够正确地启动
或停止某一服务。
运行级别配置目录的机制使得r c . s c r i p t只在系统切换运行级别时有效。它不负责检查某一
运行级别中所有的特定服务是否都已经被启动或停止。这是s h e l l编程者的事。
还可以按照希望运行的服务来控制系统的运行级别,但是这已经超出了本书的讨论范围。
28.1 怎么知道系统中是否含有运行级别目录
r c . s c r i p t s一般保存在( 实际上是个链接,这一点我们将在后面讲述) / e t c / r c N . d或
/ e t c / r c . d / r c N . d目录下,
其中,N是一个数字。通常是7个,因为r c N . d目录的序号是从0到6,不过在系统上可能会
有另外几个目录,如r c S . d。这并不重要,这里我们只关心带有数字的目录。
如果是L I N U X系统,那么⋯⋯
(续)
如果我们使用c d命令进入这些r c N . d目录,会发现这些目录中的r c . s c r i p t s实际上是一些链
接。
28.2 确定当前的运行级别
本章不是针对系统管理员的,但是作为s h e l l编程者,应当了解r c . s c r i p t s是什么,它们是被
怎样放置到运行级别配置目录中的。顺便说一下,如果想知道当前的运行级别,可以用下面
的命令:
在‘run level’后面的数字就是当前的运行级别。后面的时间是系统最近一次重启动的时
间。
如果是L I N U X系统,那么⋯⋯
$ runlevel
2 3
第一列表示系统的前一个运行级别,第二列表示系统当前的运行级别,在这里是3。
28.3 快速熟悉inittab
运行级别目录中含有一系列启动服务的脚本。这里的“服务”可以是守护进程、应用程
序、服务器、子系统或脚本进程。在系统启动的过程中,将会启动一个名为i n i t的进程(它是
系统中所有进程的祖先)。它所要完成的一部分工作就是看看需要启动哪些服务,应当缺省地
进入哪一个运行级别。它通过查看一个名为i n i t t a b的配置文件来获得上述信息,该配置文件位
于/ e t c目录下。i n i t进程还按照该文件中的设置加载特定的进程。如果需要编辑这个配置文件,
一定要先做一个备份。如果该文件被破坏或出现“降级”错误,系统将无法正常启动,到那
时,将不得不进入单用户模式并修正该文件。
i n i t t a b文件所包含的域具有严格的格式。该文件中每个条目的格式为:
i d : r s t a r t : a c t i o n : p r o c e s s
其中,i d域是相应进程的唯一标识。
r s t a r t域所包含的数字表示运行该进程的级别。
a c t i o n域告诉i n i t进程如何对待p r o c e s s所对应的进程。这里可以有很多种动作,但是最常
第28章运行级别脚本319
下载
见的是w a i t和r e s p a w n。w a i t意味着当进程启动后等待它结束。r e s p a w n则意味着如果该进程不
存在,则启动相应的进程,如果它存在,那么只要它一掉下来就立即重新启动它。
p r o c e s s域包含了实际要运行的命令。下面是i n i t t a b文件的一部分。
该文件的第一行是系统缺省的运行级别,这里是级别3,一般都是这样。
以数字1 0到1 6开始的行启动或停止该运行级别所对应的全部运行级别脚本。例如,该文
件中有这样一行:
15:5:wait:/etc/rc.d/rc 5
它的意思是,在运行级别5应该以参数5执行脚本/ e t c / r c . d / r c,即/ e t c / r c . d / r c执行/ e t c / r c . d / r c 5 . d
目录中的所有脚本。
在上述文件的最后一行,在运行级别2、3、4和5,该进程将会始终存在,即使暂时掉下
来,大概也不会超过1 s。这一始终存在的进程是串口t t y S 1上的m i n g e t t y。该命令含有一个参
数,即终端类型为v t 1 0 0。
28.4 运行级别
i n i t进程在系统完全就绪之前所做的最后几项工作之一就是执行缺省运行级别所包含的所
有脚本。该进程是通过/ e t c / r c . d / r c或/ e t c / r c . i n i t来启动这些脚本的。它的作用是首先杀死该运
行级别所包含的进程再启动这些进程。
但是它怎么知道该启动或停止哪些服务呢? r c或r c . i n i t脚本将会使用f o r循环来依次查看相
应运行级别目录中的文件,给每一个链接名以K开头的相应脚本赋予参数s t o p; 给每一个链接
名以S开头的相应脚本赋予参数s t a r t。在运行级别切换时,上述脚本也会完成同样的工作,只
不过根据相应的运行级别来启动或停止对应的脚本。
r c N . d目录中的脚本只是一些链接—真正的脚本保存在其他的目录中。它们通常都放置
320 第五部分高级s h e l l编程技巧
下载
在/ u s r / s b i n / i n i t . d或/ e t c / i n i t . d目录中。
如果是L I N U X系统,那么⋯⋯
/ e t c / r c . d / i n i t . d
在这个目录中含有一些能够启动或停止某一服务的脚本。这些脚本的名字最好能够表示
出它所实现的功能,形如r c . <功能>,其中r c表示运行命令( run command)或运行控制( r u n
c o n t r o l),或者就像某些系统管理员所称的那样“真正关键的”(‘real crucial’)。
下面是这类文件的部分列表。
一般来说, r c . s c r i p t s都应当能够接受这样的参数:
rc.name stop:停止该服务。
rc.name start:启动该服务。
可选的参数包括r e s t a r t和s t a t u s。其他任何参数都应当给出相应的用法说明。注意,可以
手工运行这些脚本。
现在我们已经知道运行级别脚本应当具有什么样的功能,下一步就是把它们放置在相应
的r c N . d目录中。不过在此之前我们先来了解一下系统运行级别。
28.4.1 各种运行级别
系统含有七种运行级别(见表2 8 - 1 )。不同的系统在某些运行级别上稍有差别。
在将一个脚本放置在不同的运行级别目录中之前,首先应当弄清楚打算在哪一个运行级
别启动或停止相应的服务?一旦弄清楚这一点,就可以接着进行下面的步骤了。
表28-1 各个运行级别的用途
运行级别0 启动和停止整个系统
运行级别1 单用户或管理模式
运行级别2 多用户模式;部分网络服务被启动。有些系统将其作为正常运行模式,而不是级别3
运行级别3 正常操作运行模式,启动所有的网络服务
运行级别4 用户定义的模式,可以使用该级别来定制所需要运行的服务
运行级别5 有些U N I X操作系统变体将其作为缺省X - w i n d o w s模式,还有些系统把它作为系统维护模式
运行级别6 重启动
28.4.2 运行级别脚本的格式
r c N . d目录中的脚本都是一些链接,这样是为了省去不必要的副本。这些链接的格式为:
S n n n . s c r i p t _ n a m e

K n n n . s c r i p t _ n a m e
其中,
S:代表启动相应的进程
K:代表杀死相应的进程
n n:是0 0至9 9的两位数字,不过在有些系统中是0 0 0至9 9 9三位数字。在不同目录中的链
第28章运行级别脚本321
下载
接应采用同一数字。例如,如果某个服务在r c 3 . d中启动时名为S 4 5 . m y s c r i p t,那么如果希望它
在r c 2 . d中启动,应当使用链接名S 4 5 . m y s c r i p t。
s c r i p t _ n a m e:相应脚本的文件名,根据所在操作系统的不同,它们可能位于下列目录中:
/ u s r / s b i n / i n i t . d
/ e t c / r c . d
/ e t c / i n i t . d
当i n i t 进程调用相应的运行级别脚本时,杀进程按照从高到低的K序号进行,即
K23,myscript K12.named;而启动进程按照从低到高的序号进行。如果使用的是L I N U X系统,
K序号将按照从高到低的顺序执行。
28.4.3 安装运行级别脚本
如果想要安装自己的运行级别脚本,必须:
• 编写该脚本,确保它符合调用标准。
• 确信它能够启动或终止相应的服务。
• 将该脚本放置于(取决于操作系统) / e t c / i n i t . d或/ u s r / s b i n / i n i t . d或/ e t c / r c . d中。
• 在相应的r c N . d目录中按照合理的命名方式创建链接。
下面的脚本能够启动或停止一个名为r c . a u d i t的审核应用程序。该服务运行于级别3、5、4,
停止于级别6、2、1。通过查看r c N . d中的条目,我们发现序号3 5空闲,于是就使用该序号。
实际上,系统并不对使用已占用的序号作任何检查。
下面就是这个脚本。可以看到,该脚本使用了一个简单的c a s e语句来接收s t a r t和s t o p参数。
322 第五部分高级s h e l l编程技巧
下载
如果是LINUX系统,那么⋯⋯
有些L I N U X变体在启动服务时要求创建一个锁文件。如果没有锁文件,在杀死该脚本
时就可能会出现问题。
s t a r t选项将使该审核进程启动相应的审核系统,而s t o p选项将使它终止该系统的运行。当
然,在将自己的运行级别脚本放置在i n i t . d目录中之前,应该首先对该脚本进行测试。
让我们假定该脚本已经通过了测试。它能够正确地启动和停止审核服务。现在我们把该
脚本放置在相应的运行级别目录中。
在本系统中,r c N . d目录位于/ e t c / r c . d目录下,而我的运行级别脚本保存在/ e t c / r c . d / i n i t . d目
录下。如果系统目录结构与上面的不同,那么需要对下面的命令作相应的调整。
我们首先启动该脚本—记住启动脚本所使用的链接名是以S打头的。
我们已经创建了相应的链接。ls -l命令的结果显示该链接指向/ e t c / i n i t . d / r c . a u d i t文件。我
本应该在链接命令中给出全路径,不过没有这个必要。现在我只要进入其他的相关目录( r c 4 . d
和r c 5 . d )使用同样的命令就可以启动其他相应的服务。
如果希望停止某个脚本的运行,可以使用如下命令:
在其他相关目录中,也可以如法炮制,停止相应的审核服务。现在当系统重启动时(运行
级别6 ),它将被停止;在运行级别切换到2或1时也是如此。该服务在运行级别4或5中同样也
会被启动。
28.5 使用inittab来启动应用程序
我们还可以用其他的方法来启动应用程序。可以通过在i n i t t a b文件中加入相应的条目来做
到这一点。在我所管理的有些系统上,我就使用了这种方法,这倒不是因为这些系统中没有
运行级别目录,而是由于我有几个用于系统检查的脚本需要在系统刚刚就绪之后运行。使用
i n i t t a b是实现上述功能的理想途径。
第28章运行级别脚本323
下载
这里我们给出一个例子,我打算在系统运行在级别3时运行我的一个磁盘镜像检查脚本。
首先我确定该脚本能够正确运行,然后对i n i t t a b文件做备份。
$ cp /etc/initab /etc/inittab.bak
接下来编辑i n i t t a b文件,在该文件末尾加入这样一个条目:
保存并退出。
上面的一条意思是:
行首的r c . d i s k c h e c k e r是该进程在运行级别3中的唯一标识。该进程只运行一次。所要运行
的脚本是/ u s r / l o c a l / e t c / r c . d i s k c h e c k e r,所有的输出都被送到控制台。
28.6 启动和停止服务的其他方法
如果不想把/ e t c / i n i t t a b文件弄得过于杂乱,还有其他的方法可以实现启动和停止服务的功
能。大多数系统都含有一个名为r c . l o c a l的文件,一般来说也是位于/ e t c目录下。该脚本文件将
在i n i t t a b和运行级别脚本之后运行。可以在该文件中加入任何命令,或从中调用最习惯用的启
动脚本。
有些系统还在/ b i n目录下(更多的是在/ u s r / s b i n目录下)含有一个名为s h u t d o w n的脚本文件。
可以使用它来关闭某些服务。
28.7 小结
运行级别的确是一个系统管理问题。本章的目的在于:使你了解在系统启动时,如何按
照需求灵活地控制各种服务和脚本的启动。
这还意味着在系统重启动时,能够手工启动和停止某些服务。

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
173#
 楼主| 发表于 2006-8-13 19:27 | 只看该作者
第29章cgi 脚本
现在差不多每个人的P C上都安装了We b服务器,在这样一本关于s h e l l编程的书中似乎很
有必要包含一章关于c g i脚本的内容。
本章包含以下内容:
• 基本c g i脚本。
• 使用服务器端内嵌(Server Side Includes,SSI)。
• get方法。
• post 方法。
• 创建交互式脚本。
• 能够自动重载We b页面的c g i脚本。
运行We b服务器并不一定需要有网络环境,可以在本地主机上运行它。这里,我们假定
你已经安装了We b服务器( a p a c h e、C e r n等等)以及浏览器( N e t s c a p e、Internet Explorer等等)。
另外,该服务器应当允许运行c g i脚本。一般来说缺省值是禁止运行c g i脚本的,要运行,只要
将配置文件中相应的一行注释掉即可。后面我们会更详细地讨论这一问题。
如何安装并配置We b服务器已经超出了本书的讨论范围,不过我认为只需2 0分钟就可以
安装并运行一个We b服务器。本章中的例子运行于apache We b服务器下,我所使用的浏览器
为N e t s c a p e。
本章不打算深入探讨有关H T M L或We b的细节问题,因为市面上已经有大量关于这方面的
书籍。另外,如果要深入探讨H T M L的话,还要花费数章的笔墨。
29.1 什么是Web页面?
We b页面或文挡是包含有H T M L标记的文件。当浏览器连接到一个We b页面上时,浏览器
就会根据相应的H T M L标记来显示该页面。We b页面中可以含有非常丰富的信息,它可以包含
指向其他页面的链接、各种色彩、高亮标题、各种字体、直线、表格,还可以包含图像和声
音。
We b页面可以分为两类:动态的页面和静态的页面。静态的页面是用于显示信息或下载
文件。而动态的页面是交互型的,它们可以按照你所提供的信息产生相应的结果。动态页面
还可以用于显示实时变化的信息,如股票价格,或用于完成某些监视任务。如果想要执行这
种类型的处理,就需要编写脚本。
如果一个We b服务器能够交换信息脚本,那么它必须支持一种被称为公共网关接口的协
议,即大家所熟悉的c g i。
29.2 cgi
c g i是一种规范,它规定了获取信息的脚本如何从服务器中取得信息或向服务器中写入信
息。这种脚本或c g i脚本可以用任何语言来实现。最为流行的是P e r l语言,不过你将会发现,
也可以用普通的s h e l l脚本来实现(见图2 9 - 1)。
图29-1 浏览器和服务器可以通过cgi来交换信息
29.3 连接Web服务器
可以使用统一资源定位符( U R L )连接We b服务器。U R L包含两部分信息:
• 协议。
• 地址和数据。
其中,协议包括h t t p、f t p、m a i l t o、f i l e、t e l n e t和n e w s。这里我们只关心h t t p协议(超文本
传输协议)。
地址一般是D N S域名或服务器主机名,也可以是I P地址。其他数据可以是你所要访问文
件的实际路径名。
所有的连接都基于T C P协议之上,缺省的端口号为8 0。
如果We b服务器在你的本地主机上,而相应的主页为i n d e x . h t m l,那么可以使用下面的
U R L:
h t t p : / / l o c a l h o s t / i n d e x . h t m l
一般来说, i n d e x . h t m l是缺省下载的文件,即该页面是你的We b服务器的缺省页。这样,
你可以只输入如下的U R L:
h t t p : / / l o c a l h o s t /
29.4 cgi和HTM脚本
当浏览器发出下载页面的请求时, We b服务器将会对收到的U R L进行分析。如果其中含
有c g i - b i n,服务器将打开一个连接,通常是连接相应c g i脚本的管道。该c g i脚本所有的输入输
出都将通过该管道。如果该c g i脚本用于显示We b页面,那么它的输出中必须要包含必要的
H T M L标记,这样该页面才能够按照服务器所能够理解的格式被显示出来,因此我们有必要
了解一些H T M L的知识。We b服务器将该页面返回给发出请求的浏览器显示出来。表2 9 - 1列出
了一些常用的H T M L标记。
29.4.1 基本cgi脚本
所有的c g i脚本都应当位于We b服务器的c g i - b i n目录中,不过在不同的服务器中该目录会
有所不同。可以通过查看配置文件s r m . c o n f中S c r i p t A l i a s一段来改变该目录的位置,并允许该
服务器运行c g i脚本。所有的脚本文件名都应以. c g i做后缀。而其他We b页面都位于h t m l或
h t d o c s目录下,并且带有. h t m l后缀。所有的脚本都应具有这样的权限。
chmod 755 script.cgi
所有We b页面连接的缺省用户身份为n o b o d y,不过可以通过配置h t t p d . c o n f文件来改变这
326 第五部分高级s h e l l编程技巧
下载
用户使用浏览器连接
Web页面
Web服务器
(apache?)
cgi脚本获取信息,进行处
理后返回结果
一设置。尽管我曾经说过本章并不是关于We b服务器配置的,不过正好可以借这个机会检查
一下p a s s w d文件,看看n o b o d y用户的登录是否被禁止。如果想防止任何用户以n o b o d y的身份
从某一个物理端口上登录,只要在/ e t c / p a s s w d文件中该用户口令域的第一个字符前面加入一
个星号*即可。
表29-1 基本H T M L标记
< H T M L > < / H T M L > H T M L文挡的开头和结束
< H E A D > < / H E A D > 标题部分的开头和结束
< T I T L E > < / T I T L E > 主题的开头和结束
< B O D Y > < / B O D Y > 页面部分的开头和结束
< H n > < / H n > 不同层次的标题, 1代表最大的字体
< P > < / P > 段落的开头和结束
< B R > 换行
< H R > 水平线
< P R E > < / P R E > 预定义格式文本的开头和结束,其中的所有跳格、行都保持原样。
< B > < / B > 黑体
< I > < / I > 斜体
< O L > < / O L > 有序号的列表
<A HREF=url>link</A> 超文本链接
< F O R M > < / F O R M > 表单
M E T H O D p o s t或g e t方法
A C T I O N 地址
< I N P U T. . . > 数据输入
N A M E 变量名
S I Z E 以字符计的文本框的宽度
T Y P E 复选框、单选框、复位、提交
< S E L E C T. . . > 下拉式菜单
N A M E 变量名
S I Z E 要显示的列表的项数
<OPTION VA L U E > 将用户选择的值返回给N A M E变量
< / S E L E C T > 结束列表框
如果脚本不能正常工作,应当首先查看错误日志,因为所有的错误都记录在这些日志中。
如果使用a p a c h e作为We b服务器,那么相应的日志文件位于/ e t c / h t t p d / l o g s或/ u s r / l o c a l / a p a c h e / l o g s
目录下,这取决于We b服务器的安装路径。c g i脚本可以在命令行方式下运行测试,当然这时只
能看到文本形式的输出,但是这种输出结果有助于调试该脚本。
现在我们就来创建一个c g i脚本。把下面的内容输入到一个名为f i r s t p a g e . c g i的文件中,并
保存在c g i - b i n目录下。不要忘记该文件应当具有权限7 5 5。
第29章cgi 脚本327
下载
如你所知,第一行表示s h e l l解释器的路径。第一个e c h o命令行告诉服务器这是一个M I M E
题头;第二行e c h o命令行用于显示一个空行。如果在M I M E题头后面没有一个空行, c g i脚本
的输出将无法正确显示。
接着,e c h o命令输出了一个< H T M L >标记,它告诉浏览器整篇文挡应以H T M L格式显示。
H T M L文挡可以显示从最大的< H 1 >到< H n >的若干种不同字体。为了不过于费眼, < H 6 >是通
常可接受的最小字体。这里我们把文字居中,这样看起来更舒服一些。接下来,我们显示一
条水平线。最后,我们用< H 2 >字体和< C E N T E R >标记居中显示了这样一行:“Stand-By To
S t a n d - To”,该脚本的输出以< / H T M L >标记结束。
如果忘记了某一个结束标记,不要紧—你会很快发现这一点,因为在你试图浏览该页面
时,一些标记将会在浏览器中显示出来。
现在如果想浏览该页面,可以在浏览器的U R L框中输入这样一行:
h t t p : / / y o u r _ s e r v e r / c g i - b i n / f i r s t p a g e . c g i
输入时用实际的服务器名来替代上面一行中的y o u r _ s e r v e r。
如果你的机器已经联网,而你得到“ D N S查找失败”的错误提示,那可能是由于浏览器
在I n t e r n e t上查找你刚刚编写的页面。不妨查看一下浏览器的连接选项;它可能设置为忽略本
机代理,在此处键入主机名并重新运行浏览器即可。

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
174#
 楼主| 发表于 2006-8-13 19:27 | 只看该作者
29.4.2 显示shell命令输出
现在我们在脚本中加上一条s h e l l命令,这样就可以在浏览器中显示该命令的输出。
我们将显示当前登录的用户数,这通过将w h o命令的输出经管道传递给w c命令就可以实
现。还将显示当前的日期。
328 第五部分高级s h e l l编程技巧
下载
在这个脚本的开头,我们取得了当前的日期和连接数。日期居中显示。变量U S E R S也被
显示出来。通过一个i f语句来判断用户数是否少于1 0,如果是,则显示这样的信息“现在还早
或现在是晚餐时间”。
标记< P R E >保留其间的所有空格和跳格。如果希望显示系统命令的输出,如用d f命令显
示文件系统的情况,或只是使用简单的e c h o命令,那么应当使用< P R E >标记。在本例中我本
来没有必要使用< P R E >标记,但我想我还是应该及早介绍它的这种应用,这样即使读者今后
遇到这样的问题,也不会感到迷惑。要显示该页面,可以使用如下的U R L:
h t t p : / / y o u r _ s e r v e r / c g i - b i n / p a g e t w o . c g i
输入时用实际的服务器名来替代上面一行中的y o u r _ s e r v e r。
图2 9 - 3显示了刚才编辑的页面。
图29-3 脚本pagetwo.cgi的输出
第29章cgi 脚本329
下载
29.4.3 使用SSI
使用c g i脚本产生一个We b页面并显示少量信息有点杀鸡用牛刀。例如我们用c g i脚本产生
了一个页面而仅仅是为了显示当前日期。如果我们能够把c g i脚本嵌入到H T M L文挡中,让该
脚本的输出显示在普通的页面中岂不更好?这样做是可行的,下面我们就将讨论这一内容。
为了内嵌c g i脚本,我们必须使能服务器端内嵌( S S I )。这样,在显示一个页面时,它将会
把S S I命令替换为相应命令或脚本的输出。一些含有服务器和命令信息的特殊环境变量也是全
局可见的。
为了让服务器能够知道替换文挡中的相应S S I命令,需要使能S S I,应当去掉配置文件中
含有s e r v e r- p a s s e d的一行开头的注释符,在a p a c h e上是这样的:
需要重新启动We b服务器软件,使用kill -1命令使该服务器重新读入配置文件。含有S S I
的页面应当具有后缀. s h t m l,而不是. h t m l。
29.4.4 访问计数器
现在让我们来创建一个能够显示访问次数的页面。你肯定见过类似的页面:“你是第n个
访问本站点的用户”。我们还将显示该页面的最新更改时间。
不要忘记将下面的脚本放置在c g i - b i n目录中,起名为h i t c o u n t . c g i。
如你所见的,该脚本读入. . / c d i - b i n / c o u n t e r文件中的值并将其赋给变量a c c e s s,将该变量加
1,显示该变量,最后将新的值写回到. . / c g i - b i n / c o u n t e r文件中。
现在我们创建一个名为c o u n t e r的文件。我们只需在其中放置一个初始值,这里我们取1。
于是,操作步骤为:创建一个名为c o u n t e r的文件并写入1 (不要加引号),然后保存并退出。
由于每个用户都需要使用该文件,文件属主、同组用户及其他用户都应对其具有读和写
的权限。
$ chmod 666 counter
现在还需要在We b根目录下(该目录通常是放置所有其他H T M L文挡的地方,一般是h t d o c s
或h t m l目录)创建一个相应的. s h t m l文件。下面就是该文件,千万不要忘记带. s h t m l:
330 第五部分高级s h e l l编程技巧
下载
在使用S S I时L A S T _ M O D I F I E D变量及其他变量是全局可见的。可以通过访问a p a c h e的
We b站点( w w w. a p a c h e . o rg )得到所有在使用S S I时全局可见的特殊变量的详细描述。
我们来看下列的S S I命令:
它的一般形式为:
<!--#command argument="value"-->
在本例中, c g i脚本h i t c o u n t是这样运行的:
命令是e x e c。
参数为c g i。
其中的v a l u e是要运行的脚本。
我已经改变了配置文件,把这个页面作为主页,而不是i n d e x . h t m l。不过你仍然可以通过
在U R L中使用全路径来访问i n d e x . h t m l页面。
图29-4 含有点击计数器的页面
第29章cgi 脚本331
下载
如果想改变缺省页,可以编辑s r m . c o n f文件。该文件中含有这样一行:
D i r e c t o r y I n d e x
你会看到文件名i n d e x . h t m l显示在该条目中。把它改成所希望的缺省页即可。不要忘记关
闭并重新启动We b服务器以使该改动生效。
要访问该脚本,可以在浏览器的U R L框中输入:
h t t p : / / < s e r v e r _ n a m e > / m a i n . s h t m l

h t t p : / / < s e r v e r _ n a m e >
(如果该页面是缺省页的话)。
图2 9 - 4显示了刚才创建的页面;可以刷新该页面观察计数器的增加。注意, L A S T _
M O D I F I E D变量的值也被显示出来。
可以通过在c r o n中加入一行,每天夜里向c o u n t e r文件中写入1来复位该计数器的值。

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
175#
 楼主| 发表于 2006-8-13 19:27 | 只看该作者
29.4.5 使用一个链接来显示当前Web环境变量
在执行c g i脚本时,有若干环境变量可用。可以通过e n v或s e t命令看到绝大多数的变量。
我们在m a i n . s h t m l文挡中创建一个指向相应c g i脚本的链接,该脚本能够显示这些变量。
下面是我们使用的链接:
<A HREF="/cgi-bin/printenv.cgi">Environment</A>
其中A HREF是链接标记的头。相应的地址包含在双引号中。单词E n v i r o n m e n t是要显示
出来的单词,用户将点击这里。< / A >是链接标记的尾。
下面就是m a i n . s h t m l文挡:
下面是被调用的脚本p r i n t e n v. c g i,它使用e n v命令显示环境变量。在这里,我们使用
< P R E >标记来保持该命令输出中的空格和跳格不变。
332 第五部分高级s h e l l编程技巧
下载
图2 9 - 5显示了该页面。
图29-5 含有显示环境变量链接的页面
图29-6 显示当前环境变量的页面
第29章cgi 脚本333
下载
当你点击该链接时,将会显示出当前的环境设置(见图2 9 - 6 )。你在自己机器上所看到的可
能与此有所不同。在运行不同的脚本时,一些相应的环境变量值将会随之改变。
29.4.6 其他常用的环境变量
表2 9 - 2列出了最常用的c g i环境变量。其中有些变量可以用e n v或s e t命令显示出来。
表29-2 常用的cgi We b服务器变量
DOCUMENT ROOT We b服务器的主目录,是放置H T M L文挡的地方
G AT E WAY _ I N T E R FA C E c g i的版本
H T T P _ A C C E P T 可接受的各种M I M E类型
H T T P _ C O N N E C T I O N 缺省的H T T P连接
H T T P _ H O S T 本地主机名
H T T P _ U S E R _ A G E N T 客户端浏览器
R E M O T E _ H O S T 远程主机
R E M O T E _ A D D R * 远程主机的I P地址
R E Q U E S T _ M E T H O D 传递信息的方法
S C R I P T _ F I L E N A M E c g i脚本的绝对路径
S C R I P T _ N A M E c g i脚本的相对路径
S E RV E R _ A D M I N We b服务器管理员的邮件地址
S E RV E R _ N A M E 服务器的主机名、D N S或I P地址
S E RV E R _ P R O TO C O L 连接所使用的协议
S E RV E R _ S O F T WA R E We b服务器软件名
Q U E RY _ S T R I N G g e t方法所传递的数据
C O N T E N T _ T Y P E M I M E类型
C O N T E N T _ L E N G T H p o s t方法所传递的字节数
*严格来讲,这是你连接至I n t e r n e t的网关地址。
为了显示这些变量,可以把它们放在一个c g i脚本中,这样,在需要使用某个变量值时随
时都可以调用该脚本。
334 第五部分高级s h e l l编程技巧
下载
29.5 get和post方法简介
到现在为止,我们只是向屏幕上输出。要想从用户那里得到信息,我们需要使用表单,
这也是c g i为什么如此流行的原因。你需要有获得用户输入的能力。有了表单就可以显示文本
框、下拉式列表框和单选框。
在用户通过键入或选择向表单输入了一些信息之后,他可以点击发送按钮将这些信息发
送给某个脚本,在这里是c g i脚本。我们需要使用g e t或p o s t方法来收集这样的信息。
29.5.1 get方法
任何表单的缺省操作都是g e t方法。g e t方法是从静态H T M L页面获取文件的方法。
当用户点击“提交”按钮时,用户选择的信息将以编码字符串的形式附加在服务器U R L
的后面。服务器环境变量Q U E RY _ S T R I N G保存了编码字符串。变量R E Q U E S T _ M E T H O D保
存了该表单所使用的方法。
1. 创建一个简单的表单
现在让我们来创建一个简单的表单,在m a i n . s h t m l文挡中创建一个指向b o o k a . c g i脚本的链
接。
在m a i n . s h t m l文挡中上一次创建的链接后面增加这样一行:
现在就按照下面的内容创建b o o k a . c g i文件,不要忘记把它放在c g i - b i n目录中。
第29章cgi 脚本335
下载
我们在上述表单的操作项中设定:一旦用户按下“发送”按钮,脚本b o o k a _ r e s u l l t . c g i将
被执行。我们现在讨论g e t方法。
上面的表单将会显示两个文本框、两个下拉式列表框和一个复选框。
输入姓名的文本框宽度为3 0个字符,相应的输入被赋给变量c o n t a c t。
第一个下拉式列表框让用户选择最喜爱的电影,选择项被赋给变量f i l m。
第二个下拉式列表框让用户选择最喜爱的演员,选择项被赋给变量a c t o r。
用户可以通过点击选择某一个复选框或两个都选。相应的逻辑值分别保存在变量
v i e w _ c i n e和变量v i e w _ v i d中。如果用户选择某一个复选框,那么相应的变量的值为o n。
区域型文本框允许用户输入超过一行的文本,而不是像标准文本框那样只能输入一行(在
本例中是4行,每行宽3 0个字符),所有的输入都将赋给变量t e x t a r e a。
发送数据时需要使用s u b m i t作为输入类型。用户可以点击c l e a r按钮清除当前的表单。
创建如下的c g i脚本,命名为b o o k a _ r e s u l t . c g i并将其保存在c g i - b i n目录下。
上面的脚本显示了变量Q U E RY _ S T R I N G和R E Q U E S T _ M E T H O D。变量Q U E RY _ S T R I N G保
336 第五部分高级s h e l l编程技巧
下载
存了由脚本b o o k a . c g i创建的表单中编码字符串格式的所有输入数据。变量R E Q U E S T _ M E T H O D
中保存了所使用的方法,这里是get。图29-7显示了该表单。
现在我们在该表单中输入一些信息并发送(见图2 9 - 8 )。点击“发送”按钮就会看到图2 9 - 9所
示的页面。由于字符串太长,变量Q U E RY _ S T R I N G只能显示出一部分。下面是该字符串的全部。
图29-7 使用get方法的cgi表单
图29-8 在表单中选择并键入信息
第29章cgi 脚本337
下载
图29-9 该表单所发送的信息被回显出来
从我们所发送的信息可以知道, Q U E RY _ S T R I N G变量中应包含下列信息:
变量值
c o n t a c t David Ta n s l e y
f i l m The Sound Of Music
a c t o r Bruce Wi l l i s
v i e w _ c i n e 选中,则该值为‘ o n’
v i e w _ v i d 选中,则该值为‘ o n’
t e x t a r e a ! "比% $ % ^ * ^ & * ( ) * ( ) ( *
H o w ’s that!!
2. 对编码字符串解码
当用户点击提交按钮时,相应的信息被赋给了变量Q U E RY _ S T R I N G,这些信息是以下面
的格式编码的:
所有的空格用+来替代。
所有的值域用&隔开。
所有的值和相应域用=隔开。
所有的符号和一些特殊字符用% x y的形式表示,其中x y是该字符的1 6进制A S C I I码。看一
下Q U E RY _ S T R I N G变量就知道,在t e x t a r e a变量中含有很多这样的字符。
c g i协议声明,所有采用% x y形式表示的特殊字符(其中x y为1 6进制数)都被转换为对应的
A S C I I字符。这种1 6进制字符包括特殊字符&、%、+、=、(、)及所有A S C I I码超过1 2 7的其他
特殊字符。例如字符“ (”应为%2 9。
这种1 6进制字符产生于文本框,用户可能会在这些地方输入这样的字符。不过,它们也
可以出现在下拉式列表框中。
338 第五部分高级s h e l l编程技巧
下载
为了解码相应字符串,我们应当:
将所有的&替换为换行。
将所有的+替换为空格。
将所有的=替换为空格。
将所有的%x y替换对应的A S C I I字符。
在完成上述转换之后,我们可能需要访问某个变量,这样就可以根据用户发送的信息来
进行某些处理。解码只是所有工作的一部分,尽管这是最繁重的一部分。如果想访问这些变
量,可以使用e v a l命令。
下面的脚本将会完成所有必要的转换并能够访问每一个变量。该脚本的注释丰富,应该
能够理解。
你可能已经注意到,这里使用p r i n t f命令来回显所有的变量—这是因为使用它更简单。
第29章cgi 脚本339
下载
p r i n t f命令和e c h o命令的功能相似,但它可以完成所有1 6进制字符的转换。需要注意的是,在
使用p r i n t f命令时,它不会自动换行,必须要在每一行的末尾使用\ n来换行。Q U E RY _ S T R I N G
变量中的1 6进制字符是以% x y的形式来表示的,我们只要使用s e d把它们转换成\ x n n的格式(其
中n n为1 6进制数),p r i n t f命令就可以自动完成相应的转换。有简单的办法我们何必要使用复杂
的呢?
把上面的脚本存为c o n v. c g i,并放在c g i - b i n目录下。现在我们只要对脚本b o o k a . c g i做小小
的改动,就能够在表单提交时执行脚本c o n v. c g i而不是b o o k a _ r e s u l t . c g i。下面是做改动的一
行:
<FORM action="/cgi-bin/conv.cgi" METHOD=GET>
现在如果我们重新提交该表单,它将执行脚本c o n v. c g i,我们将会得到如图2 9 - 1 0所示的
结果。
图29-10 完全解码的表单输入数据
现在我们把该字符串转换成为一种更可读的形式,这样我们可以对其做进一步的处理。
在使用表单时,g e t方法是缺省的方法。根据所处的环境,使用g e t方法有两个潜在的问题。
在发送信息时,整个编码字符串都附加在服务器U R L的后面,这样所发送的信息可以从U R L
框中看到。可能你会认为这没什么大不了的,如果你是通过网络发送公司或个人的信息,这
就是一个值得注意的问题了。
如果表单具有很多的输入域,那么Q U E RY _ S T R I N G变量将会变得很长。大多数人在使用
c g i时都用p o s t作为表单输入的方法。在下一小节中,我们将对p o s t方法进行介绍。

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
176#
 楼主| 发表于 2006-8-13 19:28 | 只看该作者
29.5.2 post方法
p o s t方法的字符串编码方式与g e t方法相同。它们所不同的是获取数据的方法, p o s t方法是
340 第五部分高级s h e l l编程技巧
下载
从标准输入读入的。如果想用p o s t方法来发送数据,只要把表单操作语句中的g e t替换为p o s t即
可。
<FORM action"/cgi-bin/conv.cgi" METHOD=POST>
变量C O N T E N T _ L E N G T H中含有使用p o s t方法发送的总字节数。我们从标准输入读入该
字符串,然后进行与g e t方法一样的转换。在输入的字节数等于变量C O N T E N T _ L E N G T H的值
时,将会停止读入。
只需要改动表单处理脚本中的相应语句就可以产生一个通用的解码脚本。为了从标准输
入中读入,可以使用c a t命令。下面是需要在c o n v. c g i脚本中增加的语句,这样它就既可以适用
于g e t方法,也可以适用于p o s t方法。
注意c a t命令后面的横杠-,它允许c a t命令从标准输入中读入。
我们只测试Q U E RY _ S T R I N G变量—如果使用p o s t方法,那么就用c a t命令把所有来自于
标准输入的字符串赋给该变量。如果使用g e t方法,就无须做这样的操作,只需从该变量中读
取信息即可。
将c g i脚本b o o k a . c g i中的表单操作一行由
<FORM action="/cgi-bin/conv.cgi"METHOD=GET>
改为:
<FORM action="/cgi-bin/conv.cgi"METHOD=POST>
我们还将在c o n v. c g i脚本中做一些其他修改,这样就可以测试文本框和复选框中输入的值。
下面是修改后的脚本。
第29章cgi 脚本341
下载
注意,我使用了很多p r i n t f命令,在不需要置换字符串变量时,本可以使用e c h o命令,但
为了统一起见,我一律都使用了p r i n t f命令。
浏览上述表单并使用p o s t方法来发送数据:
h t t p : / / < s e r v e r _ n a m e > / c g i - b i n / b o o k a . c g i
图2 9 - 11显示了我所输入的信息。
在输入一些信息之后,点击“发送”按钮,结果如图2 9 - 1 2所示。
该脚本检查各个变量,看是否有相应的信息输入。还可以做进一步的改进,检查所有变
量的值,如果用户没有在某个输入域输入任何信息,那么就重新向用户显示该表单,要求用
户重新输入。如果用户提供了填写正确的表单,可以把它们附加在一个文件的末尾,创建一
342 第五部分高级s h e l l编程技巧
下载
个微型的数据表。
图29-11 使用post方法的cgi表单
图29-12 使用post方法所获得的数据被完全解码
3. 一个更为实用的c g i脚本
我们现在创建一个更为实用的脚本。这里我们虚构一个名为Wonder Gifts的公司,按照用
第29章cgi 脚本343
下载
户的选择显示该公司的报表。
一个会计文件包含了该公司1 9 9 8年每一个季度每一个部门的销售额。该文件中包含下列
部门:文具、图书、礼品。
我们的任务是按照用户的选择生成一个报表。用户可以按照季度或部门进行选择。收到
用户选择后的处理过程就是,将所选择的部门和季度中所有月份的销售额加在一起。输出可
以是屏幕、打印机或两者皆有。
我们的表单有两个下拉式列表框,一个用来选择部门,一个用来选择季度。有一个单选
框用于选择输出形式。使用单选框时,用户只能选择其中之一。实际上报表只输出到屏幕上,
这里的单选框只是一个演示。
下面就是原始的数据文件,它包含以下的域:
部门:年:季度:该季度1至3月份的销售额
下面是表单脚本。
344 第五部分高级s h e l l编程技巧
下载
其中,变量d e p t将保存用户所选择的部门;而变量q t r用于保存用户所选择的季度。变量
s t d o u t可能出现的值有p r i n t e r、s c r e e n、b o t h,缺省为屏幕(缺省值由关键字C H E C K E D指定)。
下面的脚本用于处理所接收到的信息。
第29章cgi 脚本345
下载
该脚本的第一部分和其他使用p o s t方法的表单处理脚本没有什么区别。由于这里没有1 6进
制字符需要转换(因为输入域都是预定义的下拉式列表框),就不需要使用p r i n t f命令,不过你
完全可以使用该命令。这里有意思的部分就是从q t r _ 1 9 9 8 . t x t文件中读入信息的一段。
在w h i l e循环中分别将原始文件中的几个域赋给变量D E P T、Y E A R、Q、P 1、P 2、P 3、P 4。
然后比较$ d e p t (这个值是由用户给出)和变量D E P T的值;如果匹配,再比较$ q t r (这个值由用户
给出)和变量Q的值,如果也匹配,那么就将这一行中的所有数据相加。
现在我们已经有了表单脚本和处理表单所发送的信息的脚本,现在来试着运行它。在浏
览器的U R L框中输入如下的U R L (或在主页中加入另外一个链接):
h t t p : / / < s e r v e r _ n a m e > / c g i - b i n / g i f t s . c g i
结果如图2 9 - 1 3所示。
图29-13 选择季度信息供进一步处理
346 第五部分高级s h e l l编程技巧
下载
对用户输入信息处理后返回的页面如图2 9 - 1 4所示。
图29-14 处理结果
29.5.3 填充列表项
要想使页面成为真正的动态页面,可能需要动态地使用某个文件中的信息来填充列表项,
而不是把它们编写进c g i脚本。
在下面的脚本中,下拉式列表框中的选项是由l i s t文件中的信息填充的,该文件位于We b
服务器根目录下的t e m p目录中。在这个脚本中,使用了一个w h i l e循环来读入文件中的内容(一
次读入一行),并将读入的信息填充到列表框选项中。相应的填充语句为:
echo "<OPTION>$LINE"
被用户选择的项赋给变量m e n u _ s e l e c t i o n。
下面就是填充下拉式列表框的脚本,这里没有指定表单的操作。
第29章cgi 脚本347
下载
29.5.4 自动刷新页面
在使用c g i脚本实现监视或看门狗功能时,如果能够让页面不断自动刷新就方便多了。想
要实现这样的功能,需要不断调用自己的脚本或页面。下面的命令将每隔6 0秒刷新一次
d f s p a c e . c g i脚本。
<meta http-equiv="Refresh" content=60;URL=http:/linux.pc/cgib
i n / d f s p a c e . c g i " >
这里的关键字是R e f r e s h。这样We b服务器就知道应该重载该页面。c o n t e n t = 6 0则表示每次
刷新的间隔秒数。只要在U R L中包含相应的脚本名就能够不断刷新该页面。
我有好几个监视脚本在实时运行,它们不断轮询网络中所有的主机,这样我一眼就能够
看出每个机器是处在运行状态还是关闭状态。为了更美观,我使用了一个红色的小球和一个
绿色的小球来分别代替文字o n和o ff。
下面的脚本在一张表中显示出d f命令输出中的两列:磁盘占用情况和文件系统名。
下面的一段只显示了表头。在使用表格显示系统命令输出结果时,需要经过反复调整才
能达到令人满意的效果。
c e l l s p a c i n g设置了表格内框和外框的间距。b o r d e r则用于控制表格的边框宽度。c o l s决定
了表中所显示的列数。
下面是该脚本的实质部分:
在上面一段脚本中,使用d f命令显示文件系统的情况,并将结果通过管道传递给s e d命令,
删除其中的题头,然后再通过管道将结果传递给a w k命令,取其中的第5、6列,将结果分别赋
给变量p e r c e n t和m o u n t。
T R代表表格行,T D代表表格数据。这是表格中存放信息的地方。
的确,对于监视文件系统来说, 6 0秒刷新一次有些太夸张了,但是如果你正在文件系统
间进行大文件的迁移,这个脚本就能够使你掌握每一分钟的最新情况!
下面就是该脚本。
348 第五部分高级s h e l l编程技巧
下载
在你浏览器的U R L框中输入如下的U R L:
h t t p : / / < s e r v e r _ n a m e > / c g i - b i n / d f s p a c e . c g i
你就会看到如图2 9 - 1 5所示的输出(在你的机器上所看到的文件系统状态多半与此不同)。
图29-15 使用表格实时显示df命令的输出
29.6 小结
使用c g i脚本可以创建更为有趣的用户界面。H T M L页面可以作为任何处理过程的前端界面。
我们可以编写用于监视、显示、数据库查询等的脚本。H T M L现在已经成为很多应用程
序文挡的标准格式。

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
177#
 楼主| 发表于 2006-8-13 19:28 | 只看该作者
附录常用shell命令
本附录中列举了一些有用的s h e l l命令。这里并没有完全列出每个命令的各种选项,不过
对于理解该命令是足够了。
这些命令的其他一些例子散布于本书的各个部分。
basename
格式:
basename path
b a s e n a m e命令能够从路径中分离出文件名。通常用于s h e l l脚本中,请看下面的例子:
如果上面的语句是脚本m y s c r i p t中的一部分,那么它的输出应为:
myscript: give me a file
其中,$ 0是一个包含当前脚本全路径的特殊变量。
cat
格式:
cat options files
选项:
- v:显示控制字符。
c a t是最常用的文本文件显示命令。
$ cat myfile
上面的命令用于显示m y f i l e文件。
$ cat myfile myfile2 >>hold_file
上面的命令把两个文件( m y f i l e和m y f i l e 2 )合并到h o l d _ f i l e中。
在脚本中c a t命令还可以用于读入文件。
compress
格式:
compress options files
选项:
- v:显示压缩结果。
c o m p r e s s命令可以用来压缩文件。压缩后的文件名具有‘ . Z’后缀。还可以使用该命令解
压文件。
cp
格式:
cp options file1 file2
选项:
- i:在覆盖文件之前提示用户,由用户确认。
- p:保留权限模式和更改时间。
- r:拷贝相应的目录及其子目录。
要将文件m y f i l e拷贝到m y f i l e 1 . b a k,使用:
$ cp myfile1 myfile1.bak
要将文件g e t . p r d从/ u s r / l o c a l / s y b i n目录拷贝到/ u s r / l o c a l / b i n目录,使用:
要将/ l o g s目录下的所有文件及子目录拷贝到/ h o l d / l o g s目录中,使用:
$ cp -r /logs /hold/logs
diff
格式:
diff options file1 file2
选项:
- c:按照标准格式输出(见下面的例子)。
- I:忽略大小写。
我们使用c o m m命令中的例子,d i ff命令将显示两个文件中不一致的行。
d i ff命令显示出两个文件中的第2行和第3行,它们的第3列不一致。
dircmp
格式:
附录常用s h e l l命令351
下载
dircmp options directory1 directory2
选项:
- s:不显示相同的文件。
d i r c m p命令与d i ff命令十分相似—它比较并显示两个目录中的不同。
dirname
格式:
dirname pathname
该目录正好和b a s e n a m e相反,它返回路径部分:
du
格式:
du options directory
选项:
- a:显示每个文件的大小,不仅是整个目录所占用的空间。
- s:只显示总计。
d u显示的磁盘空间占用是以5 1 2字节的块来表示的。它主要用于显示目录所占用的空间。
在本例中, / v a r目录所占用的空间为1 4 9 2 9块(每块5 1 2字节)。
file
格式:
file filename
该命令用来确定文件的类型。
fuser
格式:
fuser options file
选项:
- k:杀死所有访问该文件或文件系统的进程。
352 附录常用s h e l l命令
下载
- u:显示访问该文件或文件系统的所有进程。
f u s e r命令可以显示访问某个文件或文件系统的所有进程。在有些系统上- u和- m选项可以
互换。还可以在i f语句中使用f u s e r命令。
要列出设备/ d e v / h d a 5上的所有活动进程,使用:
要杀死设备/ d e v / h d a 5上的所有进程,使用:
$ fuser -k /dev/hda5
要查看d o c _ p a r t文件是否被打开,有哪些进程在使用,可用:
有些系统上的f u s e r命令能够在列表中显示用户登录I D。如果你的系统不具有这样的功能,
可以按照f u s e r命令输出中末尾含有‘ e’的数字在ps -ef或ps xa命令的输出中用g r e p命令查找
相应的用户登录I D。
head
格式:
head -number files
h e a d命令可以显示相应文件的前1 0行。如果希望指定显示的行数,可以使用- n u m b e r选项。
例如:
$ head -1 myfile
只显示文件的第一行,而
$ head -30 logfile |more
则显示l o g f i l e文件的前3 0行。
logname
格式:
l o g n a m e
该命令可以显示当前所使用的登录用户名:
mkdir
格式:
mkdir options directory
选项:
附录常用s h e l l命令353
下载
- m:在创建目录时按照该选项的值设置访问权限。
上述命令创建了一个名为H O L D _ A R E A的目录。
more
格式:
more options files
该命令和p a g e及p g命令的功能相似,都能够分屏显示文件内容。
选项:
- c:不滚屏,而是通过覆盖来换页。
- d:在分页处显示提示。
- n:每屏显示n行。
$ more /etc/passwd
上面的命令显示p a s s w d文件
$ cat logfile |more
上面的命令显示l o g f i l e文件。
nl
格式:
nl options file
选项:
- I:行号每次增加n;缺省为1。
- p:在新的一页不重新计数。
n l命令可用于在文件中列行号,在打印源代码或列日志文件时很有用。
$ nl myscript
上面的命令将列出m y s c r i p t文件的行号。
$ nl myscript >hold_file
则将上面命令的输出重定向到h o l d _ f i l e文件中。
$ nl myscript | lpr
将上面命令的结果重定向到打印机。
printf
格式:
printf format arguments
该命令有点类似于a w k命令的p r i n t f函数,它将格式化文本送至标准输出。
其中,格式符f o r m a t包含三种类型的项,这里我们只讨论格式符:
%[- +]m.nx
354 附录常用s h e l l命令
下载
其中横杠-为从行首算起的起始位置。一般说来m表示域的宽度而n表示域的最大宽度。
‘%’后面可跟下列格式字符:
s:字符串。
c:字符。
d:数字。
x:1 6进制数。
o:1 0进制数。
p r i n t f命令本身并不会产生换行符,必须使用转义字符来实现这样的功能。下面是最常用
的转义字符:
\ a:响铃。
\ b:退格。
\ r:回车。
\ f:换页。
\ n:换行。
\ t:跳格。
$ printf "Howzat!\n"
H o w z a t !
上面的命令输出了一个字符串,使用\ n来换行。
上面的命令把1 6进制值转换为A S C I I字符+。
上面的命令从左起第1 0个字符的位置开始显示字符串。
pwd
格式:
p w d
显示当前的工作目录,可以用:
在上面的脚本中,使用了命令置换来获得当前目录。
rm
格式:
rm options files
选项:
附录常用s h e l l命令355
下载
- i:在删除文件之前给出提示(安全模式)。
- r:删除目录。
r m命令能够删除文件或目录。
上面的第二条命令能够删除/ v a r / s p o o l / t m p目录下的所有文件及子目录。
rmdir
格式:
rmdir options directory
选项:
- p:如果相应的目录为空目录,则删除该目录。
$ rmdir /var/spool/tmp/lp_HP
上面的命令将删除/ v a r / s p o o l / t m p目录下的l p _ H P目录。
script
格式:
script option file
- a:将输出附加在文件末尾。
可以使用s c r i p t命令记录当前会话。只要在命令行键入该命令即可。该命令在你退出当前
会话时结束。它可以将你的输入记录下来并附加到一个文件末尾。
$ script mylogin
将会启动s c r i p t命令并将所有会话内容记录在m y l o g i n文件中。
shutdown
格式:
s h u t d o w n
该命令将关闭系统。很多系统供应商都有自己特定的命令变体。
$ shutdown now
上面的命令将会立即关机。
$ shutdown -g60 -I6 -y
上面的命令将会在6 0秒之后关机,然后重新启动系统。
sleep
格式:
sleep number
该命令使系统等待相应的秒数。例如:
356 附录常用s h e l l命令
下载
$ sleep 10
意味着系统在1 0秒钟之内不进行任何操作。
strings
格式:
strings filename
该命令可以看二进制文件中所包含的文本。
touch
格式:
touch options filename
选项:
-t MMDDhhmm 创建一个具有相应月、日、时分时间戳的文件。
下面的命令能够以当前时间创建文件或更新已有文件的时间戳。
上面的命令以当前时间创建了一个名为m y f i l e的文件。
上面的命令以时间戳6月1 0日上午9 : 3 0创建了一个名为m y f i l e 2的空文件。
tty
格式:
t t y
可以使用t t y来报告所连接的设备或终端。
可以使用tty -s命令来确定脚本的标准输入。返回码为:
0:终端。
1:非终端。
uname
格式:
uname options
选项:
- a:显示所有信息。
- s:系统名。
- v:只显示操作系统版本或其发布日期。
附录常用s h e l l命令357
下载
要显示当前操作系统名及其他相关信息,可以用:
uncompress
格式:
uncompress files
可以使用该命令来恢复压缩文件。
$ uncompress myfile
上面的命令解压缩先前压缩的m y f i l e文件。注意,在解压缩时不必给出. Z后缀。
wait
格式:
wait process ID
该命令可以用来等待进程号为process ID的进程或所有的后台进程结束后,再执行当前脚
本。
下面的命令等待进程号为1 2 9 9的进程结束后再执行当前脚本:
$ wait 1299
下面的命令等待所有的后台进程结束后再执行当前脚本:
$ wait
wc
格式:
wc options file。s
选项:
- c:显示字符数。
- l:显示行数。
- w:显示单词数。
该命令能够统计文件中的字符数、单词数和行数。
在上面第一个例子中, w h o命令的输出通过管道传递给w c命令,该命令显示出如下的几
列:
行数、单词数、字符数
在上面的第二个例子中, w c命令只显示文件中所包含的行数。
358 附录常用s h e l l命令
下载
上面的脚本显示出变量VA R中所包含的字符串的长度。
whereis
格式:
whereis command_name
w h e r e i s命令能够给出系统命令的二进制文件及其在线手册的路径。
注意,在下面的例子中, w h e r e i s命令没有显示出相应命令的二进制文件路径,因为它们
是内建的s h e l l脚本,但是该命令给出了其在线手册的路径。
who
格式:
who options
选项:
- a:显示所有的结果。
- r:显示当前的运行级别(在L I N U X系统中应当使用r u n l e v e l命令)。
- s:列出用户名及时间域。
whoami 显示执行该命令的用户名。这不是w h o命令的一个选项,可以单独应用。
w h o命令可以显示当前有哪些用户登录到系统上

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表