Chinaunix首页 | 论坛 | 博客
  • 博客访问: 83071
  • 博文数量: 21
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 185
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-30 17:02
文章分类

全部博文(21)

文章存档

2008年(21)

我的朋友

分类: LINUX

2008-09-01 12:51:42

Unix/Linux 平台任务的自动化(二)

11.3 Perl 
   
  Perl 是从awk发展起来的,它由Larry Wall在1986年发明。它是一种功能强大的编程语言,而且可以在许多平台上使用。实际上,你完全可以将 Perl作为一种标准编程语言( 不是脚本语言)来使用,笔者非常喜欢它,并且建议所有不想学习C语言的UNIX管理员应该掌握Perl的基本编程技术。 目前,常用的版本是perl 5,几乎所有的Linux发行版本都会包含它,缺省时,linux的perl 5安装在/usr/bin下,命令是/usr /bin/perl.

11.3.1 基本语法 
 
   
  perl的语法介于C和basic之间,一个perl程序由若干行组成,使用的时候由perl解释程序解释执行。每个完整的行都应该用分号结尾。 
   
  Perl的基本语法是这样的: 
   
  ① 变量和运算符 
   
  在perl中,所有变量都不需要提前声明。一旦对某个变量赋值,就自动产生了这个变量。perl的变量有普通变量,数组和关联数组三种。普通变量就是数值和字符串,要声明一个普通变量,在变量名字前面加上$,例如 
   
  $string1="aaa"; 
   
  $test=5; 
   
  $u=1.33; 
   
  同样,访问变量内容也需要使用$符号。 
 
   
  数组用@字符标志,如 
   
  @name1=("tom","marry","john"); 
   
  $b=$name[0]; $b现在等于"tom" 
   
  $b=@name[0];跟上一句是一样的 
   
  $name[0,2]=["help","so"];现在@name等于[“help","marry","so"] 
   
  @name[0,2]==@name[2,0];交换0,2元素 
   
  数组的大小不是固定的,你可以动态地添加数组元素,例如 
   
  $name[3]="app";增加一个元素 
   
  直接访问数组名字将得到数组中元素的个数,例如: 
   
  $count=@name;将name的元素个数存放到$count变量中。 
 
   
  关联数组是一种特殊的数组,每个元素都由一对元素构成。或者说,关联数组是一种下标不是整数的数组,要声明一个关联数组,使用%符号,例如: 
   
  %arr=(1,"one",2,"two",3,"three",4,"four"); 
   
  这时可以用前面的值(key)来索引后面的值: 
   
  $one=$arr{1};这时$one等于"one" 
   
  注意关联数组的访问方式,是使用$关联数组名字[索引号]。 
   
  你可以把关联数组看成数据库的一种实现。与一般的数组一样,其大小也可以动态调节: 
   
  $arr{5}="five";增加一对数据。 
   
  可以将关联数组简单地变成普通数组,例如 
   
  @X=%arr;现在@X的内容是X[0]="1",X[1]="one",…………… 
   
  perl的运算符与C语言以及我们介绍的gawk很相似,包括普通的+-*/%以及来自C语言的逻辑运算符&&(和),||(或),等等,下面是一个列表: 
   
   + - * /     四则运算,注意perl的除法是浮点除法 
   
  $a % $b     a对b取余数,例如3%2的结果是1 
   
  $1 .. $2    区段运算符,这个算符取出$1和$2中间的所有值,例如1..9返回一个表 
1,2,………9。通常用这个命令初始化一个数组,例如:@dec=1..9;@oth=(1..26,'A'..'Z')等等。 
   
  =     赋值算符 
   
  >   < >= <= == != 
   
  这几个算符是数字之间的比较算符。 
   
  perl中没有专门的boolean型变量,而是象C语言一样认为所有不为零的量为真值,而0或者空字符串为假。与C语言类似,Perl支持以下的逻辑运算符: 
   
  &&  与 || 或 ! 非  
   
  同样,perl也支持位运算: 
   
  &  与  || 或 ^ 异或 
   
  还有就是与C语言相似的运算符使用方式,如 
   
  $i+=$j;  等效于$i=$i+$j,同样还可以使用$i-=5;$i&=12。这样的算式 
   
  $i++;  等效于C语言的++,将i加一,++$i,$i--,--$i都是可以使用的。 
   
  除了上面的标准算式之外,perl支持字符串运算,首先是字符串之间的比较命令: 
   
  $str1 gt $str2   $str1大于$str2 
   
  $str1 lt $str2   $str1小于$str2 
   
  $str1 ge $str2   $str1不小于$str2 
   
  $str1 le $str2   $str1不大于$str2 
   
  $str1 eq $str2   $str1等于$str2 
   
  $str1 ne $str2   $str1不等于$str2 
   
  $str1 cmp $str2   根据$str1是大于,等于还是小于$str2,返回1,0或者-1。 
   
  上面的字符串比较都是使用字典顺序,即ASCII码的顺序。 
   
  另一个非常有用的运算符是点号运算符,这个运算符用于把两个字符串连接成一个,例如: 
   
  $str1="string1"; 
   
  $str2="string2"; 
   
  $string3=$str1.$str2;这时$string3等于"string1string2" 
   
  ②基本语句和函数: 
   
  #  
 
   
  这个符号代表注释的开始。 
 
   
  print  
 
   
  显示字符串,写文件,如 
   
  print "hello\n";或者print "the var is $i","\n";注意变量名会自动地被替换成变量值,除非你用一个\符号明确地告诉perl: 
   
  print "\$i is a str"; 
   
  print FILE "hello\n";向FILE对应的文件写,FILE是一个文件句柄; 
   
  split 分割字符串,格式split(/模式/,$string); 
   
  例如$string="i:am:perl"; 
   
  @list=split(/:/,$string); 
   
  #这时@list=("i","am","perl") 
   
  ($a,$b,$c)=split(/:/,$string); 
 
   
  delete $ARRAY(key) 
 
   
  这个函数用于在关联数组中删除一对记录。例如,%arr=(1,”one”,2,”two”,3,”three”); delete $arr(2);执行上述操作之后,%arr的内容变为(1,”one”,2,”two ”)。 
 
   
  keys(%ARRAY)  
 
   
  取出关联数组%ARRAY中所有的索引key。这个操作将返回一个数组。例如,对于上面的%arr,执行@test=key(%arr)的结果是@test成为(1,2)。 
 
   
  values(%ARRAY)  
 
   
  取出关联数组%ARRAY中所有的value,同样返回一个数组,例如对于%arr,@test=values(%arr)的结果是@test变成(”one”,”two”)。 
 
   
  reverse(@array)  
 
   
  把@array反转排列。例如@test=(1,2,5,3,10),@other=reverse(@test)的结果是@other变成(10,3,5,2,1)。 
 
   
  sort(@array)  
 
   
  排序,注意这个排序是按照字符串的排序,例如@other=sort(@other)的结果是(1,10,2,3,5)。 
 
   
  chop($string)  
 
   
  删除字符串的最后一个字符,通常用于去掉输入字符串中的回车符。 
 
   
  lenth($string)  
 
   
  取字符串长度 
 
   
  substr($string,offset,length)  
 
   
  取字符串子串,即从$string的offset偏移量处截取length长度的字符串作为子串返回 
 
   
  index($string,$substring)  
 
   
  在$string中查找$substring,成功的话,返回$substring在$string中的偏移量,如果不存在就返回-1。 
 
   
  push(@array,$string)  
 
   
  在@array末尾加入$string 
 
   
  pop(@array) 
 
   
  删除@array的末尾元素并返回这个元素 
 
   
  shift(@array) 
 
   
  删除@array的开头元素并且返回这个元素 
 
   
  join($string,@array)  
 
   
  在@array中间加入$string并返回结果 
 
   
  grep(/pattern/,@array) 
 
   
  在@array中用正则方式查找符合条件的元素 
 
   
  hex($string) 
 
   
  将16进制转化为十进制 
 
   
  rand  
 
   
  产生随机数,注意应该先执行srand初始化随机数种子。 
 
   
  localtime  
 
   
  返回时间数组 
 
   
  die LIST  
 
   
  显示字符串并且退出程序 
 
   
  pack("格式”,LIST) 
 
   
  把一个LIST转换成指定的二进制格式,例如:$string=pack('C",65)这时$string等于ASCII的65,即"A" 
 
   
  反引号 
 
   
  用反引号将某个字符串括起来的效果是使perl执行系统命令,这里使用的反引号是大键盘最左边键,如`ls`执行ls命令。 
 
   
  ③使用文件 
 
   
  在perl中使用文本文件非常简单,只要使用open和close打开和关闭文件: 
 
   
  open 打开文件 
   
  close 关闭文件 
 
   
  open 函数的格式是open(Filehandle,$filename),这个操作将会打开$filename文件,并且让Filehandle句柄指向打开 的文件。如果失败,将返回false。缺省下,文件是以只读的方式打开的。如果要打开名字为$filename文件用于输出,使用 open(Filehandle,">$filename")。想要在某个文件的后面追加内容,使用 open(Filehandle,">>$filename")。当然,open(Filehandle,"<$filename") 也是可以使用的,不过这就等于open(Filehandle,"$filename")。 
   
  read 读文件,格式是read (Filehandle,$string,length),这函数从Filehandle指向的文件中读取length个字符,存放到$string变量中。如果你要得到标准输入,使用STDIN的句柄。 
   
  close (Filehandle)将关闭由open语句打开的文件。 
   
  除了用read语句的标准方法之外,还有一个经常用的方法: 
   
  $filecontent=;从句柄FILE指向的文件中读取一行,内容存入$filecontent变量。如果你要从控制台读取一个字符串,使用$input=;就可以了。 
   
  下面是一个例子: 
   
  $filename="test"; 
   
  open (FILE,"$filename")||die "can not open file!; 
   
  while($line=
   
  print "$line"; 
   

   
  close(FILE); 
   
  这 个程序实际就是cat命令的perl语言实现,open命令打开当前目录下面的test文件,并且把句柄返回到FILE变量,注意这一行的用法,Perl 的||(或)运算是短路求值的,如果open成功,那么返回一个非0的数,因此这算式无论如何都会为真,所以会跳过||后面的东西;否则,如果open失 败,perl就要对后面的东西执行一下,于是退出这个程序。 
   
  打开成功之后,perl会得到这个文件的句柄,下面的句子就是反复读取文件的每一行并且显示出来,当文件读到末尾的时候,$line=将产生一个空字符串,于是while循环结束。 
   
  与shell脚本语言类似,perl还有一些文件测试运算符 
 
   
  -t $file  
 
   
  如果$file这个文件可读,返回1,$file是文件名。 
 
   
  -w $file  
 
   
  如果$file可写,返回1 
 
   
  -x $file  
 
   
  如果$file可以执行,返回1 
 
   
  -e $file  
 
   
  如果$file存在,返回1 
 
   
  -o $file  
 
   
  如果用户是$file的拥有者,返回1 
 
   
  -s $file  
 
   
  返回$file文件的大小 
 
   
  -f $file  
 
   
  是否为正常文件 
 
   
  -T $file  
 
   
  是否文本 
 
   
  -B $file  
 
   
  是否二进制文件 
 
   
  -M $file  
 
   
  文件从更新到现在的日期数 
 
   
  ④流程控制 
 
   
  perl支持与C语言很相似的流程控制语句: 
 
   
  if和if..else: 
   
  if语句的语法是 
   
  if(...){ 
   
  clause; 
   


与C语言不同,即使只有一行程序,if后面的花括号也不能省略,这一点也适用于后面说的其他复合语句。 
   
  与C语言类似,也可以用else和elseif子句: 
   
  if(...){ 
   
  clause1;} 
   
  else { 
   
  clause2; 
   

   
  或者 
   
  if (…){ 
   
  ... 
   

   
  elseif(…){ 
   
  .... 
   

   
  else{ 
   
  ... 
   

   
  另外,perl还支持unless语句: 
   
  unless(exp1){ 
   
  clause1; 
   

   
  如果exp1不成立,就执行clause1子句。这个unless语句里面也可以使用else子句。实际上,这就是一种否定形式的if……else语句。 
 
   
  while循环语句: 
   
  while的语法有两种,分别是将表达式放在循环首部和尾部,第一种形式是: 
   
  while(exp){ 
   
  clause; 
   

   
  第二种形式是 
   
  do { 
   
  clause; 
   

   
  while(exp); 
   
  都是循环执行clause直到exp不成立,不过一个在循环头部判断exp表达式是否为真,另一个是在循环尾部。 
 
   
  until循环 
 
   
  语法是until(exp){ 
   
  clause; 
   

   
  反复执行clause直到exp成立。 
   
  for循环 
 
   
  for(初始化;继续条件;增量){ 
 
   
  循环体; 
   

 
   
  这个for循环和C的一样,首先执行初始化语句,然后开始循环执行循环体,每次循环都调用一次增量表达式,直到循环继续条件不再成立。例如 
   
  for ($1=0;$i<10;$i++){ 
   
  print $i; 
   

   
  将显示出从0到9的所有整数。 
 
   
  foreach $variable(@array){ 
 
   
  循环体; 
   

 
   
  这个类似于shell语言的foreach,它把@array的内容一条一条赋给$variable并执行里面的语句。 
 
   
  跳出循环 
   
  有两个语句用来实现特殊控制: 
 
   
  last if 用在循环里,相当于break; 
   
  next if 相当于continue. 
 
   
  ⑤文字处理运算 
 
   
  除了正常的字符串处理语句外,perl还支持一种文字处理运算方式,基本格式是$string=~(文字处理模式)。这个文字处理模式是perl的主要优点之一,由于perl的文字处理运算模式太强大了,这里只能介绍几个非常基本的形式。 
   
  首先解释一下pattern的概念.pattern一般是用两个/字符夹在一起的一些字符串, 用来代表一些具有某些特点的字符串, 实际上,这个patternj基本上就是grep/egrep里面的正则表达式,只是功能更丰富一点。常用的有: 
   
  任意字符串: 匹配该字符串  
   
  [0-9]  匹配所有数字字符 
   
  [a-z]  所有小写字母 
   
  [^0-9]  所有的非数字 
   
  [^a-z]  所有的非小写字母 
   
  [A-Z]  所有的大写字母 
   
  ^   字符串开头的字符 
   
  $   字符串结尾的字符 
   
  \d   跟[0-9]一样 
   
  \D   非数字字符 
   
  \w   就相当于[a-zA-Z0-9] 
   
  \W   相当于[^a-zA-Z0-9] 
   
  \s   一个空白的字符 
   
  \S   非空白的字符 
   
  \d+   一个相当于数字的字符串 
   
  \w+   一个完全由数字或字符构成的字符串 
   
  \b   一个不由英文字母或者数字为边界的字符串 
   
  \B   一个由字母或数字为边界的字符串 
   
  a|b|c  符合a,b,c之一的字符串 
   
  /pattern/i  i代表忽略大小写 
   
  []   找寻符合[]内的字符,例如[abde]可以匹配a,b,d,e的任何一种 
   
  ? {m}  正好是m个指定的字母 
   
  {m,n}  多于m少于n个指定的字符 
   
  \   如果要引用一些在pattern中具有特殊意义的字符,使用\前缀 
 
   
  在perl的文本运算模式中,最常用的是=~或者!~运算符号和s,tr两个函数。=~表示匹配,它用右边的模式来匹配左边的字符串,如果成功就得到一个true,!~正好相反,代表不匹配,例如 
   
  $string="chmod711cgi"; 
   
  if($string=~"/chmod/"){ 
   
      print "Found chmod!\n";} 
   
  $string=~"/chmod/"这样的表达式询问是否/chmod/可以匹配$string,因为$string中包含chmod,所以if语句会成功地执行。 
   
  tr是串转换函数,例如: 
   
  $string=~tr/a-z/A-Z/; 
   
  将字符串中的小写字母转换成大写. 
   
  s是串取代函数,例如: 
   
  $string=~s/a/A/; 
   
  把第一个a换成A,还可以加后缀g表示全程替换,例如: 
   
  $string=~s/1/A/g; 
   
  变换后,$string变成chmod7AAcgi. 
   
  注意tr和s的区别,tr的多替换一般是一对一的,或者说是字符的替换,而s是字符串的替换,长度可以改变,例如如果$string的值是chmod711cgi,那么 
   
  $string=~s/1/ONE/g; 
   
  将变成chmod7ONEONEcgi.而 
   
  $string=~tr/1/ONE/; 
   
  将把$string变成chmod7oocgi。 
   
  还有一个很实用的功能是变数替换,例如: 
   
  $string="test24"; 
   
  $string=~s/(\d+)/<$1>/; 
   
  这时,s首先搜索满足\d+(数字)的串,得到24,然后送入$1,接着再套上<>,结果是 "test<24>". 
   
  ⑥内置变量 
   
  除了用户定义的变量之外,perl还定义了一些内置变量,它们在perl中有特殊的意义,用户不能修改它们的含义(有些可以赋值),下面是常用的内置变量: 
   
  @ARGV 
   
  这 是个数组,它代表的是传递给perl程序的命令行开关,如@ARGV[0]是第一个参数,@ARGV[1]是第二个等等。如果你的perl程序名字叫 test,而你用test me other去调用它,那么@ARGV[0]是”me”,@ARGV[1]是other,以此类推。 
   
  $_和$1,$2,……… 
   
  这几个参数用于文本处理模式中的临时变量。举个例子来说,串匹配模式中: 
   
  $string="chmod711cgi" 
   
  $string=~/(\w+)\s+(\d+)/; 
   
  看 上去这第二行代码什么也不做,因为它仅仅是个匹配语句。不过,实际上,由于perl会把临时变量放进$n变量,所以它会修改$_和$1,………变量。在这 个匹配模式中,首先的\w+匹配一组字符,成功,得到chmod字符串,于是perl将它保存到$1;然后,\s+匹配一组空白符号,失败;最后,\d+ 匹配一组数字,成功,得到711,perl将它保存到$2。 
   
  如果在匹配模式中没有指明对那个串变量使用匹配模式,就使用$_进行匹配。 
   
  ⑦自定义函数 
   
  Perl程序中允许定义自己的子程序。例如,下面的语句定义了一个子过程: 
   
  sub my_proc { 
   
  print “this is my subrouting\n”; 
   

   
  sub是子过程的说明,my_proc是过程名字,要调用这个过程,只要使用&符号,例如: 
   
  if($want==1){ 
   
  &my_proc; 
   
  }                                                                          
                                                                             
                                                                             
                                                           
   
  11.3.2 perl的使用 
   
  上 面介绍了perl的基本语法。要使用perl,你当然可以在交互模式下使用,但是,一般情况下,我们用perl是代替shell脚本完成自动化任务的。为 此,我们需要把perl写成程序来运行。写perl程序可以用任何文本编辑工具创建,一般总是设置其扩展名为.pl,虽然实际上扩展名是不需要的。 
   
  要运行一个perl程序,有两种方法,一种是调用perl解释器读入perl源程序,例如,我们已经写了一个perl程序,命名为test.pl,那么,可以用下面的命令执行它: 
   
  $ /usr/bin/perl test.pl 
   
  不过,在一般情况下,我们更喜欢在命令行下面直接敲入程序的名字执行它,为此,可以在perl程序的头部加入这样的行: 
   
  #!/usr/bin/perl 
   
  注 意#!符号,它告诉shell应该用什么程序来解释当前脚本,这里的定义是/usr/bin/perl,这是缺省的的perl安装位置。如果你的perl 可执行程序放在别的目录下,自己修改这一行。这样,当shell读到这个文件的时候,就会自动启动perl来解释这个程序。 
   
  perl最常用的功能是用来写cgi程序,不过,我们不想涉及cgi程序的细节。相反,我们介绍如何用perl进行日常管理,用perl程序代替书写晦涩的shell脚本。 
   
  让 我们从一个我自己的例子开始,我经常要把一些txt文本直接转化成html文本,以便做进一步的编辑和主页发布,其实这个操作非常简单,就是将回车和大于 号,小于号都换成对应的HTML标记,这可以用word或者netscape来完成,但是如果涉及的文件数目比较多或者文件比较大,用这些软件就很困难 了,所以我写了一个十分简单的perl脚本: 
   
  #!/usr/bin/perl 
   
  if((@ARGV[0] eq "")||(@ARGV[1] eq "")) { 
   
  print "convert inputfile outputfile\n"; 
   
  exit;} 
   
  open (FILE1,"@ARGV[0]")||die"can not open source file!\n"; 
   
  open (FILE2,">@ARGV[1]")||die "can not open taget file!\n"; 
 
   
  while($line=){ 
 
   
  $line=~s/   
  $line=~s/>/>/g; 
   
  $line=~s/\^M//g; 
   
  $line=~s/\n/
/g; 
   
  print FILE2 $line; 
 
   

   
  close (FILE1); 
   
  close (FILE2); 
   
  这个程序简单得几乎象是DOS的批命令,首先检查参数是否定义,然后从输入文件中读取行,把回车和两个尖括号换成对应的html标记,写入对应文件,任务就完成了。要使用它,比如把test.txt转换成test.html,可以直接执行: 
   
  ./convert.pl test.txt test.html 
   
  perl也可以完成更复杂的操作,最常见的功能扩展是进行网络编程,如直接使用电子邮件,电子新闻服务等等。不过我们这里不能进一步介绍它的强大功能。对perl感兴趣的朋友,可以进一步查阅有关书籍学习编程技术。 
   
  11.4 其他工具 
   
  还有很多自动化脚本工具,例如python等等。另外,对于一个职业的系统管理人员,熟悉C语言的编程是很有好处的。 
   
  就 我个人而言,我感到,如果你不想学习shell,那么了解expect和perl就足以对付一般的系统管理工作。另外,还有一些威力强大的可编程工具,一 个是我们刚才提到的python,这是一种面向对象的脚本平台,如果你的大部分任务使用shell和expect,那么这个东西可能很适合你使用。 
   
  另 外一个非常有争议的产品是emacs。这个编辑工具是GNU计划的头号产物,随着发展,它已经从原来一个文本编辑程序发展成为一个使用lisp宏控制,几 乎可以做文本界面下的一切事情的集成环境。反对它的理由主要是它的运行速度在低配置的机器上几乎无法忍受,而且配置起来也十分困难。不论如何,使用 emacs有时显得比较有专业特色,至少是很有GNU的特色。


阅读(741) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~