Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103682262
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: LINUX

2008-05-04 15:36:40

 



第一章:打造函式库


Unix最大的优势其中一点,就是它可以让您把几个指令连结成一个全新的,完全符合您的工作需求的指令。尽管Unix裡头有好几百个指令,也可以变换成几千种的组合方式,但是你有时候也许会碰到一些使用现有的指令而无法解決的问题。本章的重点,就是想告诉您如何利用Shell Scripts来建立一些好用的程式。

首先我们必须先告诉各位一个秘密:Shell Scripts並不像一般真实的开发程式,如Perl、Python甚至是C语言等,拥有严谨的架构以及功能強大的函数库,不过,它可以以让你「量身订造」出自己的世界。本章的程式将告诉你如何做得到,你可以将其视为一组工具,它将让我们在本手记中写出更好、更聪明、更精鍊的scripts。

撰写Scripts最大的挑战,莫过於面临不同Unix系统间些微的差异。虽然IEEE POSIX试图提供一个跨Unix平台的共用基础,但是,对一个经常使用Red Hat Linux的朋友,再来改用Solaris的时候,就会造成一定的困扰。因为每一种操作系统指令並不是完全相同的,也会存放在不同的路径,况且使用的参数也不一樣,你不难想象,这些差異都给於撰写scripts带来一定的困难。


什麼是POSIX ?


早期Unix系统的发展过程就像是美国西部的牛仔拓荒时期,由多家不同的公司,分別发展出不同的Unix系统,同时向他们的客戶保証能相容於其他Unix系统的承诺,那真是Unix的战国时代。后来由美国电子电机工程协会(IEEE)出面介入此事,它联络了所有主要的Unix的制造供应商,提出了让大家满意的提议,针对所有商业版本与开放源始码的Unix系统,后来建立了一个称为POSIX的Unix标準。现在在市面上是买不到名为POSIX的作业系统,但是所有的Unix与Linux都要尊循这个标準。


这些相容POSIX的Unix还定会有一些差異。例如,我们在稍后会介绍的echo指令,有一些版本可以利用-n的参数来关闭自动換行的预设功能,也有一些版本利用「c」的方式来指定不进行換行,另外也有一些版本根本不认得这些参数,也沒有提供关闭換行的功能。让事情变得更加扑朔迷离的是,在同一个作业系统中,有些此Shell环境內建了不认得 -n与「c」的echo功能,但是在/bin目錄底下,又有一个独立的echo指令,可以使用这两个参数。这种情況让shell scripts的处理变的十分棘手,在理想情況下,shell scripts应该要能夠在各种Unix环境下工作。一个好用的shell scripts,不用說,一定可以让echo指令正常的执行,这是本手记众多scripts中的一个。


我们现在就开始第一支程式吧!

#1 寻找程式是否在PATH中


使用环境变数的Script程式(像是MAILER及PAGER)会有一些隐藏的危险,可能有部份的设定是指向不存在的程式。举例来說,在显示Script程式的输出时,如果我们选择以较有弹性的PAGER设定来取代一个制式的特有工具,我们要如何确保PAGER是指向一个已存在的程式呢? 如果是一个不存在的程式,则script将会停止运作。下面的这个script会帮我们确认程式是否存在於PATH中,同时它也是一个在不同工作环境中使用script技术(包含方程式与变数)的良好示范。


程式码





:*************************************************************

注意:

Script程式该放哪
我建议你可以在家(home)目录下新增一个名为『scripts』的新目录,并且将其完整的路径加在PATH的变数中。我们可以利用echo $PATH指令来观察正确的PATH,并且透过编辑『.login』或『.profile』的档(视所使用的shell决定)来修改PATH,以符合我们的需求。

***************************************************************



在执行这个Script程式之前,我们这必须在这段程式代码后再附加一段程式码,它会依照前面执行的传回值进行判断:






现在我们便可以在执行后直接显示结果。当我们执行程式后,如果你觉得这段程式码会造成混乱,可以考虑将它移除或者将其註消掉。



结果

我们分別準备三个档案来测试inpath程式:第一个是存在的档案、第二个也是存在的档案,但它的路径並不在PATH的设定中、第三个档案我们会输入完整的路径与档名,但它並不存在。







改进与加強

或许这个程式较特別的部份是利用POSIX的变数宣告方式:${var%${var#?}}。我们来探讨这个表示式,其实它是个表面繁杂,但实际上卻是两个巢状的字串。在巢状字串裡层的是${var#?},用来分离var变数第一个字元后的字串(? 是一个万用字元,代表著任何一个字元)。接著外层的 ${vat%pattern} 将移除与pattern(即里层运算后的结果)相符的字串,再產生一个字串。依我们这个script来看,产生出来的字串将是第一个字元。

这是相当复杂的解释。但关键就在checkForCmdInPath的运作。由於变数可能是单独的档名(echo)或是完整的路径与档名(/bin/echo),checkForCmdInPath必须分辨出两者的不同,它会去检查这种变数的第一个字元是否「/」因此我们必须先将变数的第一个字元分离出来。

如果POSIX的变数让你觉得恐慌,bash与ksh支援另一种变数方法:${varname:start:size},这个方式可以直接从变数varname中的第『start』个字元撷取『size』个字元。举例来說${varname : 0 : 1},将会从varname变数中的第1个字元开始,共撷取1个字元。当然,如果还是不喜欢这种撷取字元的方法,也可以考虑另一种系统:$(echo $var | cut -c1)。


注意:
#47管理工具的章节是一个很有用的script,而且与本节息息相关。它会在使用者的工作环境中确认目录位置与PATH。




#2有效的输入:字母与数字


我们经常忽视格式的要求,在输入资料的过程中,使用不正确的格式或语法。身为一个script的开发者,当我们在输入资料时,必须要避开或者纠正这种错误防止这些问题的发生。

最常遇到的情况,通常跟档案名称或是资料库的关键字有关。我们应该在输入资料前就给予提示:只能有大小写字母及数字,不能有标点符号、空白字示或间隔。希望大家能够做到。现在让大家来测试这个script测试吧!



程式码






原理

这是一个直线式思考的逻辑。第一、它将输入的字符串利用sed模式建立出一个新字符串,之后会把新字符串与输入字符串做比对。如果两个字符串相同,表示符合规定;如果不一样,则输入的字符串便不符合我们的规定,即只能输入字母与数字。此例子中较特别的是sed命令替换掉不在 [: alnum : ]设定中的所有字符。[: alnum: ]在此处的POSIX语法中当作所有的大小写字母及数字。此时compressed变量的值如果与先前输入的值不吻合,程式将会移除字串中所有的英文字母与数字,仅留下不恰当的字串并且传回1。



执行

这个特定的程式是独立运作的。在执行时它会有输入的提示讯息,并在输入之后立刻判断输入数据是否正确。这个Script是一个典型的方程式,它可能在其它的函式库或Script中出现,像是「#12建立Shell script函式库」。对于一个程式开发技术而言,它也是一个不错的范例。在你想要把它结合成一个较大且复杂的程式前,我们先来个测试。



结果






改进与加强

这个「移除要的字元,之后看看剩下什么」的方式非常好用,因为它具有很大的弹性。如果想留下大写字母,而且也要留下空格、逗号、句号。你可以这么做:





想要测试电话号码的输入格式是否正确(包括数字、空格、括号与减号),可以这么做:





只能输入数字,你可以试着这样做,不过得特别小心:





你是否允许输入负数呢? 如果說你将原本的数值都加上了负号,像是 -3-4,在程式中这也算是合法的数值,不过实际上,它並不是一个正确的数值。笔者会在「#5合法的整数输入」中,說明如何处理负号的特定问题。




#3 标準化日期格式


对於shell scripts程式的开发者来說,数据的资料格式不一致是一个很大的问题,要让它们能夠标準化亦是一个相当棘手的问题。日期的格式是眾多问题的其中一个,因为日期的表示方式有许多种,即使我们使用「月日年」的方式来表示,我们也可能有不同的输入方式:月份的部份我们可以输入英文的月份缩写或大写的全名。

基於这个理由,我特別撰写一个基本的日期格式程式,这个程式对於本手记以后的script运作有相当大的帮助,特別是「#7有效的日期格式」。


程式码







原理

注意第三个判断式:





它会将所有的数字刪除,並且利用 -z来进行测试结果是不是空白字元,如果是空白字元,表示第一个字必定是数字,那麼程式会呼叫monthnoToName来做查表的动作。接下来的两行会利用cut与tr将月份的字母做分离及转換的动作。第一行是分离出第一个字元,再利用tr命令将它转換成大写字母(之前提过,以POSIX而言echo$1 | cut -cl這种写法也可以写成 ${l%${l#?}})。第二行是將第二及第三個字母转换成小写字母:






执行

为了让normdate未来能有更大的应用空间,我们把script设计成可以在命令列上输入三个栏位的程式。另外,如果你想让此程式更具互动性,你应该要提示使用者输入三个栏位。相较之下,两者之间似乎是后者较难。


结果

对於这个程式,我们希望它能夠将一个简单的日期(已知的月份名称或月份数字及四位数的年份)变成一个标準的日期格式。举例:





改进与加強

這支script有很大的擴充性,例如 #7就利用normdate來檢查輸入的日期。另方面,只要做一点点的修改,我们就可以让这支script接受不同的日期格式,例如MM/DD/YYYY或者是MM-DD-YYYY,请将底下的程式码附加在刚才我们提及的判断式前:





修改后,我们也可以键入这样的时间格式:






To be continued..........



作者: Dava Taylor




出处:南方Linux
阅读(587) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~