楼主: 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
161#
 楼主| 发表于 2006-8-13 19:20 | 只看该作者
21.2.2 使用布尔输出
可以在i f语句中使用布尔型t p u t输出。
21.2.3 在脚本中使用tput
以下脚本设置tput bel和c l为更有意义的变量名。
下面脚本改变两个视图属性,并将光标关闭和打开。
第21章创建屏幕输出237
下载
21.2.4 产生转义序列
注意,如果正在使用一个仿真器,要使光标不可见,这个操作可能会有问题。这是因为:
1) 一些仿真器并不捕获使光标不可见的控制字符。必须要求正在使用的软件仿真的制作
者修改源脚本以关闭光标。
2) tput civis命令的一些旧版本工作不正常。
关闭光标的控制字符是? 2 5 l(这是字母l),将之打开是?2 5 h。
所有控制字符均以一个转义序列开始。通常转义键后紧跟字符[。然后实际序列打开或关
闭某终端属性。
可以使用两种不同的方法产生转义序列。下面的列表依据用户系统列出两种方法。第三
种方法对于U N I X和L I N U X支持的变量均有效,因为控制序列嵌在e c h o语句中。本书将使用这
种方法。
要发送一转义序列以关闭光标:
\ 0 3 3为转义键取值, \通知e c h o命令接下来是一个八进制值。例如要反馈一个@字符,键
入:
echo “@”或者e c h o - e“\ 1 0 0”
对于系统v ,使用
echo “\ 1 0 0”
结果是一样的。
命令c l e a r表示清屏并发送光标到屏幕左上角,此位置一般也称为h o m e。在一个V T终端范
围实现此功能所需序列为E S C I J,可以使用e c h o语句发送这一序列。
对于嵌入在文本中的任何控制字符,不要试图剪切和粘贴,因为这样会失去其特殊含义。
例如,要插入控制字符,打开光标,方法如下:
e c h o ' < CT R L - V> hit the<ESCAPE> key then [?25h'
即先击< C T R L - V > ,再击退格键,确保这不是一个仿真器。然后加入一小段脚本将之
238 第四部分基础s h e l l编程
下载
打开和关闭。可以将这段脚本编成一个函数或者在后面几页找一下这段脚本。
21.2.5 光标位置
可以用t p u t将光标放在屏幕任意位置。格式为:
cup r c
r为从上至下屏幕行数, c为穿过屏幕列数。
最好将之编成函数,这样就可以把行和列的值传递给它。
当然再传递一个字符串给它也很合适。以下是稍加改动后的函数脚本。
第21章创建屏幕输出239
下载
这可以像下面这样调用:
21.2.6 在屏幕中心位置显示文本
在屏幕中心位置显示文本不是很麻烦。首先从t p u t中得到列数,然后算出所提供的字符串
长度,从t p u t列数中减去该值,结果再除以2,所得结果可用于显示的字符串的行数。
以下脚本段实现此功能。只需稍加改动即可从文件中读取各行并在屏幕中间位置显示文本。
输入一些字符,点击回车键,文本将显示在屏幕中间第1 0行。
将上述脚本编成函数,并带有两个参数:文本和行数,这样调用更加灵活,函数如下:
可使用下述格式调用上述函数:
centertxt 15“ THE MAIN EVEN”。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
162#
 楼主| 发表于 2006-8-13 19:21 | 只看该作者
21.2.7 查找终端属性
下面脚本使用t p u t访问t e r m i n f o,显示前面提到过的t p u t命令下的一些终端转义码。
240 第四部分基础s h e l l编程
下载
命令i n f o c m p从t e r m i n f o数据库中抽取终端信息,如果要查看终端定义文件的完整列表,
可使用命令:
$ infocmp $TERM
以下是t e r m p u t脚本的终端输出:
21.2.8 在脚本中使用功能键
使用c a t命令可以查看发送的任意特殊键控制序列( F 1,上箭头等),键入cat -v,然后按
任意控制键,回车,在下一行就可以知道终端发送了什么功能键。结束后按< C t r l - c >退出。
下面的例子运行c a t命令,输入键为F 1(^ [ O P ]),F 2 ( [ O Q ] ),上箭头[ ^ [ [ A ]。
有了这些信息,就可以在脚本中插入这些字符作为用户选择的另外一些方法。
下面脚本识别F 1、F 2和箭头键,取值可能不同,因此要先用c a t命令查看用户终端控制键
发送的取值。
第21章创建屏幕输出241
下载
21.2.9 使用颜色
对域使用颜色可以使数据输入屏幕看起来更加专业。下面将使用的颜色是A N S I标准颜
色,并不是所有颜色都适合于所有系统。下面列出了大部分常用颜色。
1. 前景色:
数字颜色数字颜色
3 0 黑色3 4 蓝色
3 1 红色3 5 紫色
3 2 绿色3 6 青色
3 3 黄(或棕)色3 7 白(或灰)色
2. 背景色:
数字颜色数字颜色
4 0 黑色4 4 青色
4 1 红色4 5 蓝色
4 2 绿色4 6 青色
4 3 黄(或棕)色4 7 白(或灰)色
显示前景或背景颜色格式为:
242 第四部分基础s h e l l编程
下载
<ESCAPE> [background_number;foreground_number m
21.2.10 产生颜色
产生颜色需要在e c h o语句中嵌入控制字符。这种方法适用于带有彩色终端的任何系统。
与在控制字符里一样,可以在e c h o语句里使用转义序列产生颜色。
要产生一个黑色背景加绿色前景色:
一般方法是先击< C t r l - v >,然后是< E S C A P E >键,接着是[ 4 0;32 m。本书使用这种方法。
可能发现将颜色设置与e c h o语句放在一个c a s e语句里,然后将之编成一个函数,这样做最
好。下面是作者编写的颜色函数。
要调用颜色r e d - y e l l o w(红色背景,黄色前景),方法如下:
colour red-yellow
在脚本中可以这样使用颜色:
作者终端的缺省屏幕颜色是黑色和白色。但是如果要用黑色背景加绿色前景,可插入一
个e c h o语句,同时将之放入用户. p r o f i l e文件中。
图2 1 - 2显示加入颜色设置后的基本输出屏幕。这种颜色看起来更加吸引人
第21章创建屏幕输出243
下载
图21-1 下述脚本使用颜色和tput命令所得的屏幕概貌
下面是显示图2 1 - 1屏幕的脚本:
244 第四部分基础s h e l l编程
下载
第21章创建屏幕输出245
下载
如你所见,这个脚本没有经过验证,这样也行,因为这里脚本的目标只是显示怎样为屏
幕上色。

使用道具 举报

回复
论坛徽章:
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
163#
 楼主| 发表于 2006-8-13 19:21 | 只看该作者
21.2.11 创建精致菜单
在讲述w h i l e循环时曾经创建过菜单,现在增加菜单脚本,菜单将具有下列选项:
本脚本使用r e a d _ c h a r函数,使用户在选择菜单选项时不必敲入回车键。t r a p命令(本书后
面提到)用于忽略信号2、3和1 5,这样将防止用户试图跳出菜单。
此菜单还有一些控制访问形式。授权用户可以修改和删除记录,其余用户只能增加,查
看或打印记录。带有访问级别的有效用户列表保存在文件p r i v. u s e r中。
用户运行菜单时,如果菜单名在文件中不存在,将被告之不能运行此应用并且退出。
只出于显示目的,系统命令就替换了实际的选项执行操作。执行时我们会发现用户r o o t,
d a v e和m a t t y不能修改数据库文件,而p e t e r和l o u i s e可以。
要检查用户权限,首先需要读入列表文件,忽略注释行,将其他行重定向到一个临时文
件中。
246 第四部分基础s h e l l编程
下载
下一步是读取新形成的格式化文件,变量F O U N D首先设置为假,临时文件保存名字和权
限级别。分别用用户名和权限级别设置为一个变量,然后执行测试文件中名字是否匹配U S E R。
U S E R取值是从脚本开始时w h o a m i命令中获得的。如果不匹配,则寻找其他用户,使用命令
c o n t i n u e循环进入下一步。
处理过程直至所有用户名读取和匹配完毕。如果整个文件中均未找到匹配用户名,脚本
末尾的t e s t语句捕获权限级别,对一般访问级别为1,对高级访问权限返回0。
当用户选择修改或删除记录时,基于上述函数的返回值进行了一项测试。这个例子中
p a s s w d文件被分类或列出一个目录清单。
图21-2 带有访问限制的菜单屏幕概貌
第21章创建屏幕输出247
下载
R e s t r i c t是一个只打印违规操作提示符的函数。
上述测试在一个循环里即可完成,但考虑到脚本清晰性,使用了两个文件的方法,这样
调试起来会更容易。
图2 1 - 2显示用户d a v e试图修改记录,但只具有一般权限,因此被提示权限不够。
用户可以选择q或Q退出菜单。退出时调用一个清屏函数。这样做的好处在于可以随意增
加要运行的命令,同时也增加脚本的可读性。
脚本如下:
248 第四部分基础s h e l l编程
下载
第21章创建屏幕输出249
下载
250 第四部分基础s h e l l编程
下载
这种菜单可以在p r o f i l e文件中用e x e c命令调用,用户不能够退出。它们将始终位于菜单或
菜单子选项的应用里面。这对于只使用U N I X或L I N U X应用而不关心s h e l l的用户来说是一种好
方法。
21.3 小结
使用t p u 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
164#
 楼主| 发表于 2006-8-13 19:23 | 只看该作者
第22章创建屏幕输入
屏幕输入或数据输入是接受输入(这里指键盘)并验证其有效的能力。如果有效,接受
它,如果无效,放弃该输入。
前面讲到了基于一些条件的测试函数,例如字符串长度、字符串是数字或字符型,这一
章在脚本中将继续使用这些函数。
本章内容有:
• 验证有效输入。
• 增加、删除、修改和查看记录。
• 修改脚本的工作文件。
本章开始读起来可能有些累人,因此可以先大概看一下,再慢慢细看。验证有效性的代
码量很大,这是因为为捕获所有错误,脚本必须测试几乎所有可能的错误。
现在在创建一个一般文件以修改系统地过程中逐步实现每一个任务:增加、删除、修改
和查看记录。这里也将创建一个个人文件以修改系统。记录文件D B F I L E保存下列信息:
域长度允许输入描述
职员号码1 0 数字雇员代码
名2 0 字符雇员名
姓2 0 字符雇员姓
部门- 记帐雇员所在部门
IT
服务
销售
权利
域间用冒号:分隔,例如:
<Staff number>:<First name>:<Second name>:<Department>
每一个任务即是一个完整脚本。脚本中一小部分复制于前面的两个例子。这样做是因为
本章主要用于显示怎样用文件修改系统。刚开始编写脚本时,最令人头疼的事就是将修改的
文件或数据库系统放在一起后的文档清理工作。
运行脚本应具有一些菜单选项,与任务或模块相连接或包含在文件里与菜单脚本相关的
一系列函数相连接。每一段脚本均执行t r a p命令,信号2、3和1 5被忽略。
22.1 增加记录
将记录加入文件,包含以下两个步骤:
1) 确认输入有效。
2) 将记录写入文件。
第一个任务就是将一些函数放在一起,这些函数测试域是字符型或数字型及域的长度限
制,即数据输入有效性检验。有效性检验将用于增加数据和修改数据。幸运的是前面已经编
好这些函数,检测字符串及长度的函数脚本如下:
检测字符串是否为数字型,函数脚本如下:
检测字符串是否为字符型,函数脚本如下:
当域读取完毕时,调用相应函数,测试其返回值。
这里也需要提示以保存屏幕信息直到键入某键删除这些信息,下列函数用到了
r e a d _ a _ c h a r函数。
第22章创建屏幕输入253
下载
当用户输入雇员代码后,要确保编号还没有用到,此域必须唯一。测试这一点有几种方
法,这里使用g r e p。g r e p搜寻字符串_ C O D E中的雇员编号,如果a w k返回空值,则不存在匹配
编号,函数返回状态码0。函数如下(这里在g r e p中使用“ $ _ C O D E \ >”抽取相应匹配,变量
用双引号括起来,如果用单引号,则返回空值):
以下是检测雇员编号代码段,之后继续讲解其功能。
254 第四部分基础s h e l l编程
下载
所有检测语句均在w h i l e循环中(实际上每一个数据输入域均在一单独的w h i l e循环中),
如果没有有效数据,提示返回初始读位置。
读完雇员编号,继续检测域中数据是否存在:
if ["$NUM"!=""]
如果域中没有输入数据。则不执行i f语句t h e n部分。e l s e部分在脚本结尾部分,用于显示
下列信息:
Staff Number:No Input Detec,tTehdis Field Requires a Number
t h e n部分包括对域输入数据的所有有效性检测。假定存在输入,调用a _ n u m b e r函数,测
试传输字符串是否为一数字,如果是,函数返回0,如果不是,函数返回1。基于此返回值,
设置指针NU M_ PA S S为0,表示返回值正确(数字型),设置为1,表示返回失败(非数字
型)。
然后调用函数l e n g t h _ c h e c k,参数为字符串及字符串包含字符最大数目。这里为1 0,如果
字符串长度小于1 0,则返回0,否则返回1。指针L E N _ PA S S设置为0,表示返回成功(长度不
超过最大长度),设置为1,表示返回失败(长度超出最大长度)。
接下来检测是否有重复雇员编号。调用函数c h e c k _ d u p l i c a t e,如果没有发现重复编号,设
置指针D U P L I C AT E为0,最后测试三个指针变量均为0(无错误),为此使用A N D测试,如果
条件同时成立,执行t h e n部分语句。
如果测试通过,则存在有效域。这时处在w h i l e循环中,因此需要用b r e a k命令跳出循环。
如果有效性测试任何一部分失败,即长度测试或类型测试之一不通过,返回错误信息并
显示在屏幕底部。
Staff Number : Non_Numeric or Too Many Numbers I。n Field
验证第2和第3域有效性,处理过程一样。有效性验证这次在另一个循环中。这次调用
c h a r a c t e r s函数,检验域是否只包含字符。下述脚本做名字有效性检验:
第22章创建屏幕输入255
下载
使用c a s e语句检验部门域(列表见下面),因为公司只包含5个部门,部门域必须是其中之
一。注意对每个部门有三个不同的匹配模式,可以由用户键入部门名称加以验证。如果找到
匹配模式,用户跳出c a s e语句,并显示有效部门列表。
当所有域的有效性验证完成后,将提示用户是否保存此记录,这里使用函数
c o n t i n u e _ p r o m p t Y N,前面讲过这个函数,它处理Y或N响应,用户也可以点击回车键表示缺
省回答。
如果用户选择N,进入i f语句代码段并退出脚本。如果用户输入许多记录,然后在w h i l e循
环中调用函数以增加记录,这种方法将不会返回菜单或增加记录后退出。
如果用户选择Y,保存记录。将记录加入一个文件的脚本是:
echo "$NUM:$F_NAME:$S_NAME:$DEPART">>$D。BFILE
然后显示信息通知用户记录已存入文件。s l e e p命令将脚本进程挂起1 s,以使用户有足够
的时间查看该信息。
域分隔符是冒号,文件以姓域分类,输出存入一临时工作文件,然后文件移入初始文件
D B F I L E。文件转移操作时,会测试其最后状态,如果存在问题,则通知用户该信息。
加入一个记录后,输出如下:
256 第四部分基础s h e l l编程
下载
增加记录后,D B F I L E文件内容如下:
以下是增加一个记录的完整脚本:
第22章创建屏幕输入257
下载
258 第四部分基础s h e l l编程
下载
第22章创建屏幕输入259
下载
260 第四部分基础s h e l l编程
下载
第22章创建屏幕输入261
下载
262 第四部分基础s h e l l编程
下载
22.2 删除记录
要从文件中删除记录,首先要将记录传给用户以确保该记录是正确删除的记录。得到确
认后才执行下列任务:
1) 查询记录。
2) 显示记录。
3) 确认删除。
4) 修改文件。
首先使用姓域查询记录,一旦从用户处得到需查询的姓,则使用g r e p或a w k进行处理,但
是因为此文件不会有超过1 0 0个记录,将直接从文件中执行读取操作,进行匹配测试。
如果文件包括超过几百个记录,建议使用a w k,因为使用a w k比直接从文件中读取数据
快得多,同样也比用g r e p将各域分开存入变量要快一些。
可以使用a w k或g r e p查询文件D B F I L E:
注意使用a w k时,变量用单引号括起来,如果不这样做,就不会返回任何数据。
将各域分开,并设置与其对应的变量(记住这里用冒号作分隔符)。必须改变I F S设置为
冒号。如果不这样,就不能读取记录。改变I F S设置时,最好先保存其设置,以便于脚本完成
时再恢复它。
要保存I F S,使用:
S A V E D I F S = $ I F S
将其改为冒号:
I F S = :
当用I F S完成操作后,简单的恢复它:
I F S = $ S A V E D I F S
查询记录函数为g e t _ r e c,此函数不带参数。
用户可以输入姓或q退出任务。一旦输入姓,执行测试以确保输入存在。比较好的测试方
法是:
if ["$STR"!="";]t h e n
然后是:
[-2 $STR]
第一个测试捕获只键入回车符的用户。第二个测试0长度字符串。
使用有意义的变量名从文件中读取各域,读取记录时使用计数,通过计数变化告之用户
查询记录时发生某种动作。如果发现匹配模式,调用另一过程显示此域,用户然后使用b r e a k
命令跳出循环。如果未找到匹配模式,脚本进入下一循环步。找到匹配记录后,询问用户是
否删除记录,缺省回答是n o。
第22章创建屏幕输入263
下载
使用grep -v执行记录删除,并使用字符串S T R(S T R保存用户删除的雇员姓)显示所有未
匹配记录。
g r e p命令输出重定向到一临时工作文件中。然后文件移入初始D B F I L E中,删除后执行文
件分类,输出重定向到一临时工作文件,然后再移回初始文件D B F I L E。临时工作文件可能首
先被分类,然后再移回初始文件,而不是先移后分类。
使用最后状态命令执行测试所有文件移动操作。以下是删除一个记录的输出结果:
删除记录的完整脚本如下:
264 第四部分基础s h e l l编程
下载
第22章创建屏幕输入265
下载
22.3 修改记录
实际上已经编写了修改记录的大部分脚本,这些脚本在记录删除操作中。
找到正确记录后,设置所有该记录域变量到一临时工作文件,然后使用缺省设置变量:
:{ d e f a u l t _ v a r i a b l e = v a r i a b l e }
266 第四部分基础s h e l l编程
下载
对于不想修改的域,简单输入回车键即可,然后缺省值放入临时工作变量中。在相关域
内键入新值即可修改此域。
使用grep -v执行文件的实际修改操作。除了正在被修改的记录,所有记录重定向到一临
时工作文件,这里雇员编号用作g r e p命令字符串参数:
grep -v $CODE $DBFILE >$HOLD1
然后提示用户是否保存记录。如果保存,重新修改的记录也写入临时工作文件,然后此
临时工作文件移入原文件D B F I L E中。
输出被重定向到一临时工作文件,然后将此文件分类,再移回原文件D B F I L E。最后状态
命令测试文件移动操作。如果存在问题,告之用户。实际脚本中,在增加记录时执行的有效
性测试也同样用于修改记录中。修改一个记录的输出结果如下:
完整脚本如下:
第22章创建屏幕输入267
下载
268 第四部分基础s h e l l编程
下载
第22章创建屏幕输入269
下载
22.4 查看记录
用户可能要查看所有记录或其中一部分。如果查看所有记录,使用c a t命令和a w k,如果
记录包含很多域,那么很有必要定量显示输出结果,使其对用户更加实用。
在删除和修改记录中,已经讲过了怎样显示单一记录,用户有选择的查看记录选项时唯
一增加的功能就是打印一个记录。以下脚本段将记录发往打印机:
270 第四部分基础s h e l l编程
下载
查看记录时输出结果如下:
查看记录的完整脚本如下:
第22章创建屏幕输入271
下载
272 第四部分基础s h e l l编程
下载
22.5 小结
验证用户输入的有效性很重要,也是一种高级技巧。虽然你可能有时知道记录接受输入
的内容,但用户通常并不知道。
在计算机工业发展史上有一句老话:送进的是垃圾,出来的肯定是垃圾,但知道这一点
时已经太晚了,意即如果没有在脚本中测试垃圾数据,就会输出垃圾信息。

使用道具 举报

回复
论坛徽章:
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
165#
 楼主| 发表于 2006-8-13 19:24 | 只看该作者
第23章调试脚本
s h e l l编程最烦人的一项工作是调试问题。有一些方法可以借鉴,但是最好能在问题出现
前防止大部分错误,为此应遵循以下规则。
将设计脚本分成几个任务或过程,然后在继续下一步前分别予以测试。
本章内容有:
• 一般错误。
• set命令介绍。
没有比在脚本中发现一个难以察觉的错误更令人头疼的了,然而,随着编程经验不断丰
富,查询手段也相应增加。
经常碰到的问题是忘了使用引号或在i f语句末尾未加f i。
需要牢记的一点是当s h e l l打印出一个脚本错误后,不要只看那些疑问行。而是要观察整
个相关代码段。s h e l l不会对错误进行精确定位,而是在试图结束一个语句时进行错误统计。
23.1 一般错误
23.1.1 循环错误
f o r、w h i l e、u n t i l和c a s e语句中的错误是指实际语句段不正确。也许漏写了固定结构中的
一个保留字。
下面错误打印信息d o n e,这是一个很好的线索。因为这时知道正在处理一个w h i l e语句。
回溯脚本段,检查w h i l e语句,是否漏写或错写了关键字,如d o或者正在使用的条件语句。
23.1.2 典型的漏写引号
第二个典型错误是漏写引号错误。经常要注意这个问题,因为此错误经常出现。这里给
出解决这类错误的唯一方案是在脚本中确保所有引号成对出现。
当s h e l l打印出错误行后,通常在v i编辑器中查看文件。使用v i的set nu选项调试错误,先
进入v i,然后点击< E S C >键,后跟一冒号,再键入set nu <return>,这时给出文本行号,然后
进入s h e l l打印错误行。
23.1.3 测试错误
另一个常见错误是在使用- e q语句时忘记在测试条件一边使用数字取值。
如果得到下列错误提示,通常是由于两件事情:需要在变量和方括号间加空格;在方括
号里漏写操作符。
[: missing ']'
23.1.4 字符大小写
经验上讲大多数错误是由于使用变量时大小写保持不一致。例如经常在开始定义时用大
写,然后在变量调用时用了小写字符,这样难免变量会没有赋值。
23.1.5 for循环
使用f o r循环时,有时会忘了在循环的列表部分用$符号,特别是在读取字符串时。
23.1.6 echo
最有用的调试脚本工具是e c h o命令。一般在可能出现问题的脚本重要部分加入e c h o命令,
例如在变量读取或修改操作其前后加入e c h o命令。
使用最后状态命令判断命令是否成功,这里需要注意的是,不要使用e c h o命令后直接加
最后状态命令,因为此命令永远为真。
23.2 set命令
s e t命令可辅助脚本调试。以下是s e t命令常用的调试选项:
set -n 读命令但并不执行。
set -v 显示读取的所有行。
set -x 显示所有命令及其参数。
将s e t选项关闭,只需用+替代-。有人总认为+应该为开,而-应为关闭,但实际刚好相反。
可以在脚本开始时将s e t选项打开,然后在结束时关闭它。或在认为有问题的特殊语句段
前后打开及关闭它。
下面看一个例子。以下脚本将名字保存在变量列表中。用户输入名字, f o r循环循环变量
列表查看是否有匹配模式。注意这里在脚本开始时使用了set -x,并在结尾部分关闭它。
运行此脚本,给出一个不在列表中的名字,输出如下:
第23章调试脚本275
下载
输出显示对变量列表进行循环时所有的比较操作。当读取文件或进行字符串或取值的比
较发现问题时,使用s e t命令是很有必要的。
23.3 小结
跟踪错误的最好方式是亲自查阅脚本,并使用s e t命令并加大量的e c h o语句。

使用道具 举报

回复
论坛徽章:
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
166#
 楼主| 发表于 2006-8-13 19:24 | 只看该作者
第24章shell嵌入命令
实际上已经用过了许多s h e l l嵌入命令。可能要想什么是s h e l l嵌入,这些命令是在实际的
Bourne shell里创建而不是存在于/ b i n或u s r / b i n目录里。嵌入命令比系统里的相同命令要快。
本章内容有:
• 标准的Bourne shell嵌入命令列表
例如,c d和p w d命令可同时在系统和嵌入命令中发现。如果要运行系统版,简单输入
命令路径即可:
/ b i n / p w d
24.1 shell嵌入命令完整列表
表2 4 - 1给出标准嵌入命令的完整列表。
表24-1 标准嵌入命令
: 空,永远返回为t r u e
. 从当前s h e l l中执行操作
b r e a k 退出f o r、w h i l e、u n t i l或c a s e语句
c d 改变到当前目录
c o n t i n u e 执行循环的下一步
e c h o 反馈信息到标准输出
e v a l 读取参数,执行结果命令
e x e c 执行命令,但不在当前s h e l l
exit 退出当前s h e l l
e x p o r t 导出变量,使当前s h e l l可利用它
p w d 显示当前目录
r e a d 从标准输入读取一行文本
r e a d o n l y 使变量只读
r e t u r n 退出函数并带有返回值
s e t 控制各种参数到标准输出的显示
s h i f t 命令行参数向左偏移一个
test 评估条件表达式
t i m e s 显示s h e l l运行过程的用户和系统时间
t r a p 当捕获信号时运行指定命令
u l i m i t 显示或设置s h e l l资源
u m a s k 显示或设置缺省文件创建模式
u n s e t 从s h e l l内存中删除变量或函数
w a i t 等待直到子进程运行完毕,报告终止
下面讲述一些未涉及或前面讲解不深的命令。
24.1.1 pwd
显示当前目录
$ pwd
/ t m p
24.1.2 set
在查看调试脚本、打开或关闭s h e l l选项时,曾用到s e t命令。s e t也可用于在脚本内部给出
其运行参数,以下举例说明。假定有一段脚本控制两个参数,但并不向脚本传递参数而是在
脚本内部设置其取值。可以用s e t命令完成此功能。
格式为:
set param1 param2 ..
下面的脚本设置参数为a c c o u n t s . d o c和a c c o u n t s . b a k,然后对参数进行循环处理。
当测试一段脚本且脚本包含参数时,这样使用s e t命令有很多用处。其一就是不必在每次
运行脚本时重复输入参数。
24.1.3 times
t i m e s命令给出用户脚本或任何系统命令的运行时间。第一行给出s h e l l消耗时间,第二行
给出运行命令消耗的时间。下面是t i m e s命令的输出结果:
相信以后会经常用到该命令。
24.1.4 type
使用t y p e查询命令是否仍驻留系统及命令类型。t y p e打印命令名是否有效及该命令在系统
的位置。例如:
278 第四部分基础s h e l l编程
下载
24.1.5 ulimit
u l i m i t设置运行在s h e l l上的显示限制。通常此命令定位于文件/ e t c / p r o f i l e中,但是可以从
当前s h e l l或用户. p r o f i l e文件中将之移入用户需要的位置。u l i m i t一般格式如下:
ulimit options
u l i m i t有几个选项,以下是一些常用的选项:
选项含义
- a 显示当前限制
- c 限制内核垃圾大小
- f 限制运行进程创建的输出文件的大小
例如u l i m i t取值为:
将内核文件垃圾数目设置为0:
24.1.6 wait
w a i t命令等待直到一个用户子进程完成,可以在w a i t命令中指定进程I D号。如果并未指定,
则等待直到所有子进程完成。
等待所有子进程运行完毕:
$ wait
24.2 小结
上面讲述了s h e l 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
167#
 楼主| 发表于 2006-8-13 19:24 | 只看该作者
第五部分高级shell编程技巧
第25章深入讨论<<
我们在介绍标准输入和标准输出以及w h i l e循环的时候已经几次遇到< <的应用。我们学会
了如何发送邮件,如何构建一个菜单,不过< <还有很多其他的用法。
本章将介绍以下内容:
• 快速创建一个文件。
• 自动进入菜单。
• ftp传输。
• 连接至其他应用系统。
该命令的一般形式为:
command <<word
t e x t
w o r d
这里再简要回顾一下< <的用法。当s h e l l看到< <的时候,它就会知道下一个词是一个分界
符。在该分界符以后的内容都被当作输入,直到s h e l l又看到该分界符(位于单独的一行)。这个
分界符可以是你所定义的任何字符串。
可以使用< <来创建文件、显示文件列表、排序文件列表以及创建屏幕输入。
25.1 快速创建一个文件
可以使用这种方法快速创建一个文件,并向其中存入一些文本:
$ cat >> myfile <<NEWFILE
现在可以输入一些文本,结束时只要在新的一行键入N E W F I L E即可,这样就创建了一个
名为m y f i l e的文件,该文件中包含了一些文本。
如果打开了一个已经存在的文件,输入的内容会附加到该文件的末尾。
如果使用t a b键,注意,一些老版本的s h e l l可能无法正确理解它的含义。为了解决这一问
题,可以在< <之后加一个横杠-,就像下面这样:
cat >> myfile <<- NEWFILE
. . .
25.2 快速创建打印文档
假如希望打印一小段信息,可以采用这种方法而不必使用v i编辑器。在本例中,一旦在输
入Q U I C K D O C之后按回车键,相应的文档就会被送到打印机。
第五部分高级shell编程技巧
25.3 自动选择菜单
不但可以很方便地使用< <创建菜单屏幕,还可以使用它来自动选择菜单,而不是由用户
手工进行选择。
我编写了一个菜单驱动的数据库管理脚本,可以使用它来完成备份和其他系统管理任务。
该脚本本来是在白天由用户来运行的,现在决定把这些工作交给c r o n夜间完成,我不想再另
外写一个自动运行的脚本,于是我使用< <中的输入来选择s y b _ b a c k u p脚本的菜单选项。下面
介绍一下该脚本的菜单。
主菜单如下,选择2:
第二层菜单如下,选择3:
第三级菜单如下,选择Y:
从菜单来看,如果要备份所有的数据库,需要键入:
1) 菜单脚本的名字,s y b _ b a c k u p。
2) 键入2。
3) 键入3。
4) 键入Y。
下面的脚本能够自动运行数据库备份脚本s y b _ b a c k u p:
282 第五部分高级s h e l l编程技巧
下载
该脚本中的重定向部分是:
让我们来分析一下这一部分,这里给出了脚本s y b _ b a c k u p的全路径;>>$log_f 2>&1意味
着所有的输出都重定向到$ l o g _ f中,该变量的值为/ l o g s / s q l . b a c k u p . l o g。这是一个良好的习惯,
因为这样就能够捕捉到所运行的程序或脚本的所有输出,如果出现错误的话,也能够被记录
下来。
< < M AY D AY之后的内容就是手工运行s y b _ b a c k u p脚本所需要输入的内容,直到遇到另外
一个M AY D AY结束。
这样,我就不需要重新再写一个脚本;如果已经有一个菜单驱动的脚本,只需再编写一
个使用< <输入的脚本就可以自动运行原先的脚本。
25.4 自动ftp传输
< <的另外一个流行的应用就是自动f t p传输。在使用f t p时,如果能够向用户提供一个简单
的界面就好了。下面的脚本使用了匿名用户a n o n y m o u s建立了一个f t p连接。这是一个特殊的
用户,它使得系统能够创建一个含有公共目录的安全帐户。一般来说,所有以匿名用户身份
进行连接的用户都只能从公共目录中下载文件,不过只要权限允许,用户也可以上载。
匿名用户的口令可以是任何字符串,不过最好使用主机名加上本地用户名,或电子邮件
地址。
下面的脚本将会提示如下的信息:
1) 希望登录的远程主机。
2) 文件传输的类型是二进制方式还是A S C I I方式。
3) 要下载的文件名。
4) 存放下载文件的本地目录。
当用户输入想要连接的主机之后,首先执行一个名为t r a c e r o u t e的脚本验证本地主机是否
能够连接到远程主机。如果t r a c e r o u t e执行失败,这个自动f t p传输的脚本将会再次提示用户输
入主机名。
第25章深入讨论< < 283
下载
用户在看到传输模式选择的提示之后按回车键,将会选择缺省的二进制模式。
用户在输入所要下载的文件名之后,将会被提示输入保存下载文件的本地目录。缺省的
本地目录是/ t m p。如果用户所给出的目录无法找到,仍将使用缺省的/ t m p目录。
下载文件在本地的文件名将是原文件名加上. f t p后缀。
最后,用户所有的选择都将在屏幕上显示出来,待用户确认后开始进行传输。
下面就是该脚本运行时在屏幕上的显示:
下面就是该脚本的内容:
284 第五部分高级s h e l l编程技巧
下载
第25章深入讨论< < 285
下载
在f t p命令中使用< <时,使用了ftp -i -n选项,这意味着不要自动登录,而且关闭交互模式。
这样就使得脚本可以使用u s e r命令进行登录。口令是$ U S E R @ T H I S H O S T,在这里就是
d a v e @ b u m p e r。
如果用户每天从同一台主机上下载相同的文件,比如说是包含前一天销售数据的文件,那
么用户就没有必要每天都输入同样的主机名和文件名。可以设置D E S T _ H O S T和F I L E N A M E变
量的缺省值,这样就可以使用户不必每天都输入同样的主机名和文件名。
下面是f t p自动传输脚本中提示用户输入主机名的一段,但是现在不同的是, D E S T _ H O S T
变量已设置了缺省值m y _ f a v o u r i t e _ h o s t。现在用户可以另外输入一个不同的主机名,也可以敲
回车键选择缺省值。
注意,现在不必再检查用户是否输入了一个值,因为如果用户没有输入的话,该变量将
被赋予缺省值。
25.5 访问数据库
s h e l l脚本一个常用的用途就是访问数据库系统获得信息。实现这样的功能, < <是再理想
不过了。可以用它来输入你在面对数据库提示时所做的各种选择。下面的例子并不是数据库
中的一个练习,而是为了用来介绍如何使用< <来连接其他应用程序,完成相应的任务。
对于某一个数据库系统来说,在使用某种第三方产品进行访问时, select into功能将会被
286 第五部分高级s h e l l编程技巧
下载
关闭。这意味着该数据库不能被用来插入数据或创建临时表。
为了解决这个问题,我们使用< <进行数据库连接,并使用一个f o r循环来提供各个数据库
名,一旦连接成功, < <将用来向s q l命令提供选项。
下面就是该脚本。
让我们来看一看使用< <的部分,s h e l l在执行了变量替代以后将运行下面的一段命令。
当s h e l l看到结束的分界符M AY D AY时,该脚本将开始下一次循环,对另外一个数据库进
行操作。下面就是运行的结果:
第25章深入讨论< < 287
下载
25.6 小结
本章进一步给出了一些使用< <来自动完成某些任务的例子。< <的用途很广,特别是在连
接某些应用程序或使用f t p时。你可以灵活地使用< <来自动运行以前编写的脚本,从而完成各
种不同的任务。

使用道具 举报

回复
论坛徽章:
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
168#
 楼主| 发表于 2006-8-13 19:25 | 只看该作者
第26章shell 工具
本章将讨论以下内容:
• 创建以日期命名的文件及临时文件。
• 信号。
• t r a p命令以及如何捕获信号。
• e v a l命令。
• l o g g e r命令。
26.1 创建保存信息的文件
任何脚本都应该能够创建临时文件或日志文件。在运行脚本做备份时,最好是保存一个
日志文件。这些日志文件通常在文件系统中保留几周,过时将被删除。
在开发脚本的时候,可能总要创建一些临时的文件。在正常运行脚本的时候,也要使用
临时文件保存信息,以便作为另外一个进程的输入。可以使用c a t命令来显示一个临时文件的
内容或把它打印出来。
26.1.1 使用date命令创建日志文件
在创建日志文件时,最好能够使它具有唯一性,可以按照日志文件创建的日期和时间来
识别这些文件。我们可以使用d a t e命令做到这一点。这样就能够使日期和时间成为日志文件名
中的一部分。
为了改变日期和时间的显示格式,可以使用如下的命令:
date option + %format
使用加号‘+’可以设置当前日期和时间的显示格式。下面的例子将日期以日、月、年的
格式显示:
下面是一些常用的日期格式:
下面的命令可以使时间按照h h : m m的格式显示:
下面的命令可以显示完整的时间:
注意,如果希望在日期和时间的显示中包含空格,要使用双引号。
在文件名中含有日期的一个简单办法就是使用置换。把含有你所需要的日期格式的变量
附加在相应的日志文件名后面即可。
在下面的例子中我们创建了两个日志文件,一个使用了d d,m m,y y的日期格式,另一个
使用了d d,h h,m m的时间格式。
下面就是这个脚本。
运行上面的脚本后,得到这样两个日志文件。
26.1.2 创建唯一的临时文件
在本书的前面讨论特殊变量时,曾介绍变量$ $,该变量中保存有你所运行的当前进程的
进程号。可以使用它在我们运行的脚本中创建一个唯一的临时文件,因为该脚本在运行时的
进程号是唯一的。我们只要创建一个文件并在后面附加上$ $即可。在脚本结束时,只需删除
带有$ $扩展的临时文件即可。S h e l l将会把$ $解析为当前的进程号,并删除相应的文件,而不
会影响以其他进程号做后缀的文件。
在命令行中输入如下的命令:
这就是当前的进程号,如果你执行这个命令,看到的结果可能会有所不同。现在如果我
创建另一个登录进程并输入同样的命令,将会得到一个不同的进程号,因为我已经启动了一
个新的进程。
下面的例子中,创建了两个临时文件,并进行了相应的操作,最后在结束时删除了这些
文件。
290 第五部分高级s h e l l编程技巧
下载
当上面的脚本运行时,将会创建这样两个文件:
在执行rm /tmp/*.$$时,s h e l l实际上将该命令解析为rm /tmp/*.408。
记住,该进程号只在当前进程中唯一。例如,如果我再次运行上面的脚本,将会得到一
个新的进程号,因为我已经创建了一个新的进程。
如果文件有特殊用途的话,那么创建含有日期的文件,就可以使你很容易地查找到它们。
而且还可以很容易地按照日期删除文件,因为这样一眼就能看出哪个文件是最新的,哪个文
件是最“旧”的。
还可以使用这种方法来快速地创建临时文件,它们在当前进程中是唯一的。在脚本结束
之前,也很容易删除这些临时文件。
26.2 信号
信号就是系统向脚本或命令发出的消息,告知它们某个事件的发生。这些事件通常是内
存错误,访问权限问题或某个用户试图停止你的进程。信号实际上是一些数字。下表列出了
最常用的信号及它们的含义。
信号信号名含义
1 S I G H U P 挂起或父进程被杀死
2 S I G I N T 来自键盘的中断信号,通常是< C T R L - C >
3 S I G Q U I T 从键盘退出
9 S I G K I L L 无条件终止
11 S I G S E G V 段(内存)冲突
1 5 S I G T E R M 软件终止(缺省杀进程信号)
还有信号0,我们前面在创建. l o g o u t文件时已经遇到过。该信号为“退出s h e l l”信号。为
了发出信号0,只要从命令行键入e x i t,或在一个进程或命令行中使用< C T R L - D >即可。
发送信号可以使用如下的格式:
kill [-signal no:| signal name] process ID
使用k i l l命令时不带任何信号或名字意味着使用缺省的信号1 5。
可以使用如下的命令列出所有的信号:
第2 6章shell 工具291
下载
26.2.1 杀死一个进程
发送信号1将使一个进程重新读入配置文件。例如,你在运行域名服务( D N S)守护进程
n a m e d,现在你对域名数据库文件做了某些修改,这时不需要杀死该守护进程再重新启动,只
需使用kill -1命令向其发送信号1。N a m e d进程将重新读入它的配置文件。
下面的例子向系统中一个名为m o n _ w e b的进程发送信号9(无条件终止)来杀死它。首先
使用p s命令得到相应的进程号。
如果系统不支持ps -ef命令,那么可以使用ps xa。为了杀死该进程,我可以使用下面的两
种方法之一:
kill -9 157

kill -s SIGKILL 157
在有些系统中,不必使用- s,例如:kill SIGKILL 157。
下面的脚本将根据进程名来杀死一个进程,拟被杀死的进程名作为该脚本的一个参数。
在执行相应的命令之前,将会首先检查是否存在这样的进程。在这里使用g r e p命令来匹配相
应的进程名。如果匹配成功,则向用户提示进程已经找到,并询问用户是否杀死该进程。最
后使用kill -9命令杀死相应的进程。

使用道具 举报

回复
论坛徽章:
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
169#
 楼主| 发表于 2006-8-13 19:25 | 只看该作者
26.2.2 检测信号
有些信号可以被应用程序或脚本捕获,并依据该信号采取相应的行动。另外一些信号不
能被捕获。例如,如果一个命令收到了信号9,就无法再捕捉其他信号。
在编写s h e l l脚本时,只需关心信号1、2、3和1 5。当脚本捕捉到一个信号后,它可能会采
取下面三种操作之一:
1) 不采取任何行动,由系统来进行处理。
2) 捕获该信号,但忽略它。
第2 6章shell 工具293
下载
3) 捕获该信号,并采取相应的行动。
大多数的脚本都使用第一种处理方法,这也是到目前为止本书中所有脚本所采取的处理
方法。
如果想要采取另外两种处理方法,必须使用t r a p命令。
26.3 trap
t r a p可以使你在脚本中捕捉信号。该命令的一般形式为:
trap name signal(s)
其中,n a m e是捕捉到信号以后所采取的一系列操作。实际生活中, n a m e一般是一个专门
用来处理所捕捉信号的函数。N a m e需要用双引号(“ ”)引起来。S i g n a l就是待捕捉的信号。
脚本在捕捉到一个信号以后,通常会采取某些行动。最常见的行动包括:
1) 清除临时文件。
2) 忽略该信号。
3) 询问用户是否终止该脚本的运行。
下表列出了一些最常见的t r a p命令用法:
trap "" 2 3 忽略信号2和信号3,用户不能终止该脚本
trap"commands" 2 3 如果捕捉到信号2或3,就执行相应的c o m m a n d s命令
trap 2 3 复位信号2和3,用户可以终止该脚本
也可以使用单引号(‘’)来代替双引号(“”);其结果是一样的。
26.3.1 捕获信号并采取相应的行动
下面的例子一经运行就开始计数直至用户按< C t r l - C >(信号2)。这时该脚本将会显示出当
前的循环数字,然后退出。
在本例中t r a p命令的格式为:
trap "do_something" signal nos)
下面就是该脚本:
现在让我们来仔细分析一下该脚本。
294 第五部分高级s h e l l编程技巧
下载
trap "my_exit" 2
在本例中,由于设置了t r a p命令,所以在捕捉到信号2以后,双引号内的m y _ e x i t函数将被
执行。
函数m y _ e x i t将在脚本捕捉到信号2后被调用;用户将会看到$ L O O P变量的内容,即用户
按< C t r l - C >时的计数值。在实际中,通常捕捉到信号2后所调用的函数是用来完成清除临时文
件等任务的。
下面是该脚本的运行结果:
26.3.2 捕获信号并采取行动的另一个例子
下面就是一个捕获信号后清除临时文件的例子。
下面的脚本在运行时不断使用d f和p s命令向临时文件H O L D 1 . $ $和H O L D 2 . $ $中写入相应
的信息。你应该还记得$ $表示当前的进程号。当用户按< C T R L - C >时,这些临时文件将被清
除。
第2 6章shell 工具295
下载
上面的脚本在运行时会产生如下的结果:
当收到信号2或3时,尽管一般情况下这都不是误操作,但是为了安全起见,不妨给用户
一个选择的机会,这样用户在不小心按下< C T R L - C >后,仍然可以撤消刚才的动作。
在下面的例子中,在脚本捕捉到信号2后将会向用户提供一个选择,询问用户是否真的要
退出。这里使用c a s e语句来决定采取何种操作。
如果用户希望退出,他或她可以选择1,此时当前函数会以状态1退出,而另一个清除进
程将会据此启动。如果用户并不希望退出,那么可以选择2或不做任何选择,此时c a s e语句将
会使用户退回到脚本中原来的地方。在c a s e语句中一定要包含用户输入空字符串的情况。
下面的函数在收到信号后,将会向用户提供选择:
下面是完整的脚本:
296 第五部分高级s h e l l编程技巧
下载
当上面的脚本运行时,只要在输入任何域时按下< C T R L - C >,就会得到一个选择:是继续
运行还是退出。
26.3.3 锁住终端
下面的脚本是另一个捕获信号的例子。该脚本名为l o c k i t,它将使用一个连续不断的w h i l e
循环锁住终端。在该脚本中, t r a p命令捕捉信号2、3和1 5。如果一个用户试图中断该脚本的运
行,将会得到一个不成功的提示。
在脚本初次执行时,将会被提示输入一个口令。在解锁终端时没有任何提示,可以直接
输入口令并按回车键。该脚本会从终端读入所输入的口令,并与预先设置的口令做比较,如
果一致就解锁终端。
如果忘记了自己的口令,那么只好登录到另一个终端上并杀死该进程。在本例中没有对
口令的长度加以限制—这完全取决于你。
如果你从另外一个终端上杀死了该进程,当再次回到这个终端时,可能会遇到终端设置
问题,例如回车键不起作用。这时可以试着使用下面的命令,这样可以解决大部分问题。

使用道具 举报

回复
论坛徽章:
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
170#
 楼主| 发表于 2006-8-13 19:26 | 只看该作者
26.3.4 忽略信号
在用户登录时,系统将会执行/ e t c / p r o f i l e文件,根用户不希望其他普通用户打断这一进程。
他通常通过设置t r a p来屏蔽信号1、2、3和1 5,然后在用户读当天的消息时重新打开这些信号。
最后仍然回到屏蔽这些信号的状态。
在编写脚本时也可以采用类似的办法。在脚本运行的某些关键时刻,比如打开了很多文
298 第五部分高级s h e l l编程技巧
下载
件时,不希望该脚本被中断,以免破坏这些文件。通过设置t r a p来屏蔽某些信号就可以解决这
个问题。在这些关键性的处理过程结束后,再重新打开信号。
忽略信号的一般格式为(信号9除外):
trap""signal nos)
注意,在双引号之间没有任何字符,为了重新回到捕捉信号的状态,可以使用如下的命
令:
trap"do something" signal nos)
下面我们来总结一下上述方法。
trap ""1 2 3 15:忽略信号。
关键性的处理过程
trap"my_exit" 1 2 3 15:重新回到捕捉信号的状态,在捕捉到信号后调用m y _ e x i t函数。
下面就是一个这样的例子,其中的“关键”过程实际上是一个w h i l e循环,但它能够很好
地说明这种方法。在第一个循环中,通过设置t r a p来屏蔽信号,但是在第二个例子中,又回到
捕捉信号的状态。
两个循环都只数到6,不过在循环中使用了一个s l e e p命令,这样就可以有充分的时间来实
验中断该循环。
下面就是脚本。
第2 6章shell 工具299
下载
在上面的脚本在运行时,如果我们在第一个循环期间按下< C t r l - C >,它不会有任何反应,
这是因为我们通过设置t r a p屏蔽了信号;而在第二个循环中由于重新回到捕捉信号的状态,按
下< C t r l - C >就会调用m y _ e x i t函数。
当脚本捕获到信号时,通过使用t r a p命令,可以更好地控制脚本的运行。捕获信号并进行
处理是一个脚本健壮性的标志。
26.4 eval
e v a l命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一
次扫描无法实现其功能的变量。该命令对变量进行两次扫描。这些需要进行两次扫描的变量
有时被称为复杂变量。不过我觉得这些变量本身并不复杂。
e v a l命令也可以用于回显简单变量,不一定是复杂变量。
解释e v a l命令是怎么回事的最好办法就是看几个例子。
26.4.1 执行含有字符串的命令
我们首先创建一个名为t e s t f的小文件,在这个小文件中含有一些文本。接着,将cat testf
赋给变量M Y F I L E,现在我们e c h o该变量,看看是否能够执行上述命令。
现在我们将cat testf赋给变量M Y F I L E。
$ MYFILE=“cat testf”
300 第五部分高级s h e l l编程技巧
下载
如果我们e c h o该变量,我们将无法列出t e s t f文件中的内容。
让我们来试一下e v a l命令,记住e v a l命令将会对该变量进行两次扫瞄。
从上面的结果可以看出,使用e v a l命令不但可以置换该变量,还能够执行相应的命令。第
一次扫描进行了变量置换,第二次扫描执行了该字符串中所包含的命令cat testf。
下面是另一个例子。一个名为C AT _ PA S S W D的变量含有字符串“ cat /etc/passwd | more”。
eval 命令可以执行该字符串所对应的命令。
e v a l命令还可以用来显示出传递给脚本的最后一个参数。现在来看下面的这个例子。
在运行上述脚本时,我们会看到如下的结果(你所看到进程号可能会不一样):
在上面的脚本中, e v a l命令首先把$ $ #解析为当前s h e l l的参数个数,然后在第二次扫描时
得出最后一个参数。
26.4.2 给每个值一个变量名
可以给一个值一个变量名。下面我对此做些解释,假定有一个名为d a t a的文件:
你希望该文件中的第一列成为变量名,第二列成为该变量的值,这样就可以:
怎样才能做到这一点呢?当然是使用e v a l命令。
第2 6章shell 工具301
下载
我们用d a t a文件的第一行来解释上述脚本的执行过程,该脚本读入“ P C”和“4 8 6”两个
词,把它们分别赋给变量N A M E和T Y P E。E v a l命令的第一次扫描把N A M E和T Y P E分别置换
为“P C”和“4 8 6”,第二次扫描时将P C作为变量,并将“4 8 6”作为变量的值。
下面是运行上述脚本的结果:
e v a l命令并不是一个在脚本中很常见的命令,但是如果需要对变量进行两次扫瞄的话,就
要使用e v a l命令了。
26.5 logger命令
系统中含有相当多的日志文件。其中的一个日志文件叫作m e s s a g e s,它通常位于/ v a r / a d m
或/ v a r / l o g目录下。一个名为s y s l o g的配置文件可以用来定义记录在m e s s a g e s文件中的消息,这
些消息有一定的格式。如果想知道系统中的相应配置,可以查看/ e t c / s y s l o g . c o n f文件。该文件
中包含了用于发送各种不同类型消息的工具及它们的优先级。
这里我们并不想深入探讨U N I X和L I N U X是如何向该文件中记录信息的。我们现在只要知
道这些消息有不同的级别,从信息性的消息到关键性的消息。
还可以使用l o g g e r命令向该文件发送消息。在使用该命令之前,最好查阅连机手册,因为
在不同供应商所提供的操作系统上该命令的语法也有所不同。
不过,由于这里只涉及到信息性的消息,因此不必担心下面的命令不安全。
你可能会出于下列的原因向该文件中发送消息:
• 在某一个特定的时间段出现的访问或登录。
• 你的某些执行关键任务的脚本运行失败。
• 监控脚本的报告。
下面是/ v a r / a d m / m e s s a g e s文件的例子。在系统上所看到的相应文件可能和下面的例子有
少许差别。
l o g g e r命令的一般形式为:
logger -p -I message
302 第五部分高级s h e l l编程技巧
下载
其中:
- p:为优先级,这里只涉及到提示用户注意的优先级,这也是缺省值。
- i:在每个消息中记录发送消息的进程号。
26.5.1 使用logger命令
可以使用如下命令:
可能需要等几分钟才能看到该消息被记录到m e s s a g e文件中。
如你所见,发送这一消息的用户也被记录了下来。
现在来创建一个小小的脚本,用它来记录当前系统中的用户数。该脚本可以在一天的时
段中记录系统的使用率。只要把它放进c r o n t a b文件中,使它每3 0分钟运行一次即可。
运行下面的脚本。
$ test_logger
现在来看看m e s s a g e文件的末尾:
26.5.2 在脚本中使用logger命令
向日志文件中发送信息的一个更为合理的用途就是用于脚本非正常退出时。如果希望向
日志文件中发送消息,只要在捕获信号的退出函数中包含l o g g e r命令即可。
在下面的清除脚本中,如果该脚本捕获到信号2、3或1 5的话,就向该日志文件发送一个
消息。
第2 6章shell 工具303
下载
这样只要看一下这个日志文件就可以知道脚本的运行结果是否正常。
除了使用l o g g e r命令对一些关键性的脚本处理过程做日志外,我还用它来记录使用调制解
调器连接系统的用户。下面的一段脚本记录了从串口t t y 0和t t y 0 2连接到系统中的用户。这部分
代码来自于我编写的一个/ e t c / p r o f i l e文件。
304 第五部分高级s h e l l编程技巧
下载
当希望在系统全局的日志文件中记录信息的时候, l o g g e r命令是一个非常好的工具。
26.6 小结
理解信号和对信号的捕获可以使脚本的退出更为完整。通过在系统日志文件中记录信息,
你或系统管理员就能够更容易地发现存在的问题。

使用道具 举报

回复

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

本版积分规则 发表回复

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