perl学习笔记1

如何debug一个perl程序
--5.6版本或更高,
#!/user/bin/perl –w
Use warnings;--此时会报告编译错误,但不会终止程序运行
Use diagnostics;--查看更详细的诊断说明,但程序会启动很慢(向内存中加载警告和详细说明)

$ perl –M diagnostics ./my_program—避免每次都加载内存,比较方便,直接显示错误信息


单引号与双引号的区别
单引号—除了单引号和反斜线字符,所有字符都代表自己;标示反斜线字符本身,需要在其前面再加一个反斜线;
‘hello world\n’—输出hello world\n
'hello'\\n'—会报错Backslash found where operator expected at test.pl line 1, near "'hello'\"
print 'hello\'\\n' –输出hello'\n
双引号
--\代表转义字符
“hello world\n”—输出hello world,后面紧接换行符

如何连接字符串
采用’.’--”hello ”.”world”等同于”hello world”
“justin” X 3—等同于”justinjustinjustin”


获取用户输入
--,获取用户行输入,会等待
$line = ;
If ($line eq “\n”) –用户输入换行符,

Chomp
--去除行尾的换行符
Chomp($text = )等同于 $text =; chomp($text);

Qw
--建立字符串列表,不必输入引号;
Qw( fred barney betty dino )也可以qw< a b c >或qw# qa qb qc #
($a[0], $a[1], $a[2], $a[3]) = qw/a b c d/;
@a = qw/ a b c d /;

POP/PUSH操作符
@array = 5..9;
$a = pop(@array);--@array为(5,6,7,8),$a为9
Pop @array;--@array现在是(5,6,7)
Push(@array,0)--@array现在是(5,6,0)

Shift/unshift操作符
@a = qw# dino fred barney #;
$m = shift(@a);--$m为dino,@a为(“fred”,”barney”)
Unshift(@a, ‘asd’);--@a现在为(“asd”,”fred”,”barney”)

字符串数组内插
@a = qw( a b c);
$email = “fred@a.edu”—则会内插@a数组
应写为
$email = “fred\@a.edu”或者$email = ‘fred@a.edu’;

Foreach控制结构
@rocks = qw/ bed slate lava /;
Foreach $rock (@rocks) {
 $rock = “\t$rock”;
 $rock .= “\n”;
}
循环结束后,控制变量会恢复成循环执行之前的值

$_ “老地方” 默认变量
--当未告知perl使用哪个变量视,自动使用$_
Foreach (1..10) {
  Print “ I can count to $_ \n”;
}

$_ = “Yahoo \n”;
Print;--默认打印$_

Reverse
--读取列表的值,并按相反的次序返回该列表
@a = 6..10;
@a = reverse @a;-- 此时a的值10,9,8,7.6
Reverse @a;-- 语法错误


Sort
--读取列表的值,并且根据内部的字符编码的顺序,进行排序;对ASCII编码的字符串,则按ASCII码排序
@rocks = qw/ a b c d /;
@rocks = sort @rocks; --排序后为a b c d


标量上下文/列表上下文
--列表上下文产生元素的列表;标量上下文则会返回数组中元素的个数
@a = qw( d z a );
@b = sort @a;--列表上下文a,d,z
$n = 42 + @a;--标量上下文:42 + 3,得45
@backward = reverse qw / a d c/--变成a,c,d
$backward = reverse qw / a d c/--变成cda,标量上下文
$fred = somethind;--列表上下文
($fred) = somethind;--标量上下文

清空数组
@betty = ( );
@betty = undef;--得到一个列表,且仅有一个元素;清空失败

强制指定标量上下文
--在列表上下文的地方,强制引入标量上下文,可以使用伪函数scalar
@rocks = qw( a b c d );
Print “ I have “, @rocks,” rocks \n”;--输出各种石头的名称
Print “ I have “, scalar @rocks, “ rocks \n”;--输出石头的数量

列表上下文中的
--标量上下文中返回输入数据的下一行;列表上下文中返回所有剩下的行,直到文件结尾,从键盘输入的按control-D标示文件结尾;
@lines = ;--列表上下文读取标准输入
Chomp(@lines);--
Chomp(@lines = );--读入所有行,且去除换行符

一次读入的是400M的日志文件,perl会全部读入,会占用至少1G的内存,因为perl通常浪费内存来节省时间;



子程序
--使用sub定义,可以在程序的任何地方
--可以在任意表达式中使用子程序名,用&调用
--子程序最后一次运算的结果会被自动当成返回值
$n = &max(10.15);
参数列表被传入子程序,数组变量为@_,在子程序执行期间有效;子程序的第一个参数存储于$_[0],第二个为$_[1];
--私有变量
Sub max {
  My($m,$n);--私有变量
  ($m,$n) = @_;
  If ($m > $n) {$m} else {$n}
}
--限制长度可变的参数列表
Sub max{
  If (@_ != 2) {
Print “ &max should get exactly 2 arguments \n”;
  }
}
--更好的&max子程序
--采用high-water mark算法
$maximum = &max(3,5,10,6,4);
Sub max {
  My($max_so_far) = shift @_;--将数组中的第一个值,暂时当做最大值
  Foreach (@_) {--遍历数组中的其他元素
If ($_ > $max_so_far) {
  $max_so_far = $_;
}
  }
$max_so_far;
}
非标量返回值,可以返回列表值
--想取出某段范围的数字
Sub list_from_fred_to_barney {
  If ($fred < $barney) {
$fred..$barney;
  } else {
  #从$fred倒数回$barney
  Reverse $barney..$fred;
  }
}
$fred = 11;
$barney = 6;
@c = &list_from_fred_to_barney;--@c的值为(11,10,9,8,7,6)

持有性私有变量
--使用state声明变量,子程序可以多次保留变量
--任意类型的变量都可以被声明为state变量
Sub marine {
  State $n = 0;
  $n += 1;
  Print “Hello, sailor number $n \n”
}

Running_sum(5,6);
Running_sum(1..3);
Sub running_sum {
  State $sum = 0;
  State @numbers;
 
  Foreach my $number (@_) {
Push @numbers, $number;
$sum += $number;
  }
 
 Say “The sum of (@numbers) is $sum”;
}
输出
The sum of (5,6) is 11;


标准输入
--作为行输入,读取到文件结尾,会返回undef,自然会跳出循环
--while (defined($line =)) { print “I saw $line”;};
钻石操作符<>
--行输入操作符特例,
--while (defined($line = <>)) { ….};
调用程序./my_program fred betty,则会依次读入文件fred/betty中的内容;切换文件时候中间不会有间断;
--<>的参数来自@ARGV数组,由perl解释器建立的,与普通数组使用一样;
--调用参数



标准输出
Print @array;--一个接一个的打印出数据中元素,之间没有空格
Print “@array”;--打印字符串,以空格间隔
Print (2+3)*4;--输出5;接着perl从print取得返回值1,再将它乘以4;

格式化输出printf
%g—按需要自动选择浮点数、整数或指数
%d—显示整数,舍掉小数点
%s—字符串;printf “%10s\n”, “Wilma”输出     Wilma;
%%--输出百分号;printf “%.2f%%”;输出0.00%
输出数组
my @item = qw { justin abc  dbc asdg };
printf "The itme are:\n".("%10s\n" x @item),@item;
输出—括号中的@item是标量上下文,而后面的是列表上下文
The itme are:
     justin
       abc
       dbc
      asdg

文件句柄
--程序里代表perl与外界之间I/O联系的名字,建议名字全部大写
--6个保留名:STDIN、STDOUT、STDERR、DATA、ARGV、ARGVOUT
./my_program Wilma—程序的输入文件来自文件dino,输出到文件wilma
Cat fred barney | sort | ./my_program | grep something |lpr
--将文件fred和barney中的内容输出并排序,然后输入到perl程序,运行完再过滤出需要的结果并发送到打印机打印

打开文件句柄
Open CONFIG, “dino”;
Open CONFIG, “Open CONFIG, “>dino”;--打开文件并向其写入信息,写之前清空原有信息
Open CONFIG,”>>dino”;--打开文件并向其追加信息
可以使用任何的标量表达式
My $file = “my_output”;
Open LOG, “> $file”;--中间有空格,避免文件名中出现’>’,导致>变成>>;
不正确的文件句柄
My $success = open LOG, “>>logfile”;
If (! $success){ ..open操作失败}

用die处理严重错误
--当程序遭遇到严重错误时,die函数会输出指定的信息到标准错误流中,并让程序立即终止,并返回不为0的退出码;
If (! Open LOG, “>>logfile”) {
  Die “Cannnot create logfile:$!”;--$!是可读的系统出错信息
}

使用warn输出警告信息
--功能与die类似,但不会终止程序运行

改变默认的文件输出句柄
--不显示指定,默认输出到STDOUT
Select BEDROCK;--接下来的print/printf将向BEDROCK句柄中输出信息
--数据输出到文件句柄时,默认都会经过缓冲处理;$| = 1;#立即刷新缓冲区

复用标准文件句柄
--打开已经被打开过的文件句柄,包括6个标准文件句柄
--open STDERR, “>> /home/oracle/.error_log”

Say
--等同于print,但行尾自动加上换行符
--输出内插数组,仍需要用引号括起来,否则数组中的元素会连成字符串
My @array = qw( a b c d);
Say @array;--输出abcd\n
Say “@array”;--输出a b c d\n


哈希
--$hash($some_key);赋值$family_name(“fred”) = “bac”; $file = $family_name(“fred”);不存在的值会得到undef;
--%访问整个hash;
%some_hash = (“foo”,35,”bar”,2.5); 也可使用直观的胖箭头 my %last_name = ( “fred” => “flintstone”, “dino” => undef);
--赋值给数组 @array = %some_hash;但是排列顺序可能会变
--%new_hash = %old_hash;%inverse_hash = reverse %any_hash发转hash

Keys/values函数
--my %hash =(“a” => 1,”b” => 2,”c”=> 3);
--my @k = keys %hash;--a,b,c
--my @v = values %hash;--1,2,3
--在标量上下文中,这两个函数都会返回哈希中键/值对的个数,计算过程不必对整个哈希进行遍历
My $count = keys %hash;--得到3

Each函数
--罗列哈希的每个键/值对
While ( ($key,$value) = each %hash ) {
  Print “$key => $value\n”;
}
--each返回键/值的顺序是乱的,如果需要依次处理哈希,对键排序
Foreach $key ( sort key %hash ) {
  $value = $hash($key);
  Print “$key => $value\n”;或者print “$key => $hash($key)\n”;
}

Exists函数
--检查哈希中是否有某个键
If ( exists $books(“justin”) ) {…..}

Delete函数
--从哈希中删除指定的键及其相对应的值
My $person = “justin”;
Delete $books($person);

%ENV哈希
--哈希获取执行环境变量,存取%ENV哈希
$ENV(PATH)



正则表达式 regular expresssion
简易模式
$_ =  “yabba dabba doo”;
If (/abba/) {…..} –表达式/abba/会在$_中寻找这4个字符组成的串,如果找到就返回真
/cake\tsprite/ --会匹配cake、一个制表符和sprite

元字符
--点号(.)配置任何单字符,换行(“\n”)除外
--反斜线(\),在任何元字符前面加上反斜线,就会使他失去元字符的作用;要得到真正的反斜线,用两个反斜线表示;/3\.1415926/得到3.1415926

简易量词
--星号(*)配置前面内容0次或多次的 /fred\t*barney/匹配fred和barney之间有任意多个制表符的串
--(.*)匹配任意字符无限多次,/red.*barney/
--(+)加号,匹配前一个条目一次以上:/fred +barney/
--(?)问号,前一个条目可以出现一次或不出现

模式分组
--()表示分组;/fred+/表示freddddd,/(fred)+/匹配fredfredfred
--反向引用;\1、\2,
$_ = “abba”;
If (/(.)\1/) {…}—圆括号中的点号匹配任何非回车字符,则同’bb’匹配
If(/y(….)d\1/) {..}—匹配y后面连续4个连续的非回车字符,并且用\1在d字符之后重复这4个字符
其中\n代表第n组括号,从左往右
$_ = "yabba";
if (/(.)(.)\2\1/) {
  print "$_ matches\n";--匹配
}
$_ = “AA11BB”;
If(/(.)\111/) {…}; --此时搜寻第111个括号会失败
If( /(.)\g{1}11/ ) {…};--搜寻第一个括号且后面跟上11

择一匹配
--竖线(|),左边或右边匹配都行;/fred|barney|betty/匹配任何含有fred或barney或betty的字符串;
--/fred( |\t)+barney/匹配fred好barney之间空格、制表符或两者组合出现一次以上的字符串,加号表示重复一次或多次
--/fred( +|\t+)barney/,两个单词间一定全是空格或制表符

字符集
--写在方括号[]中,只匹配单个字符,可以是字符集中列出的任何一个
--[a-zA-Z]匹配52个字母中的任何一个
--脱字符^,表示排除在外;[^n\-z]匹配n、-、z以外的任何字符,-前面加反斜线标志转义

字符集简写
--\d代表[0-9];\w表示单写字符[A-Za-z0-9];
--\s相当于[\f\t\n\r ],即换页、制表、换行、回车以及空格,但只是匹配其中一个字符,可以写成\s+匹配一个以上;
--\h匹配横向空白,即[\t ];\v匹配纵向空格,[\f\n\r];\R匹配任何类型的断行

反义简写
--\d、\w、\s的反义简写就是\D,\W.\S,也可写成[^d],[^w],[\s]
--/[\dA-Fa0f]+/匹配16进制数字
--[\d\D]表示任何数字或非数字,即匹配任何字符(而点号匹配换行符以外的任意字符);[^\d\D]


以正则表达式进行匹配
以m//进行匹配
--//为其简写;/^http:\/\//匹配起始的http://,也可以写成m%^http://%

/i进行大小写无关的匹配
Chomp($_ = );
If (/yes/i)—大小写无关的匹配

/s匹配任意字符
--点号无法匹配换行符,而/s可以完成这个任务;它将模式中的每个点号按[\d\D]处理
$_ = “I saw Barney\ndown at the bowling allay\n”;
If (/Barny.*fred/s)—

/x加入空白
--能够在模式里面随意加上空白,更易阅读;
--/-?\d+\.?\d*/可以改写成/ -? \d+ \.? \d* /x,使原始的空白与制表符失去意义;如果还要匹配空白与制表符,就得在前面补上一个反斜线字符;

组合选项修饰符
--在一个模式中使用多个修饰符,可以连在一起使用,先后顺序不会影响匹配的结果
If (/barney.*fred/is) {…}
同样的模式加上注释之后
If (m{
  Barney#小伙子 barney
  .*    #之间的任何东西
  Fred  #大嗓门的fred
  }six)  #同时使用/s,/i和/x

锚位
--默认情况,模式匹配的过程开始于待匹配字符串的开头,若不相符就一直往后推移;锚位可以让模式直接匹配字符串的某处
--脱字符^,表示字符串开头;美元符号$表示字符串结尾;
--/^\s*$/用来匹配空白行,如果不加前后两个锚位,则会把非空白行也一起算进去;

单词锚位
--锚位不局限于字符串的首尾;\b匹配单词边界
--/\bfred\b/只能匹配fred,无法匹配frederick/alfred,此处的单词指一连串的字母、数字与下划线的组合,也就是匹配/\w+/模式的字符;
--非单词边界锚位是\B,能匹配所有\b不能匹配的位置;/\bsearch\B/会匹配searches、searching,但不匹配search、researching;

绑定操作符=~
--默认情况下模式匹配对象为$_,而=~能让perl拿右边的模式匹配左边的字符串,而非$_;
My $some_other = “I dream of betty rubble”;
If($some_other =~ /\brub/) {…}
也可以写成如下方式:
Print “Do you like Perl?”;
My $like_perl = ( =~ /\byes\b/i);--判断回答是否为yes,不区分大小写
If ($like_perl) {…}

模式串中的内插
My $what = shift @ARGV;
While (<>) {
  If (/^($what)/) {--定位于字符串的开头
--如果第一个命令行参数是fred|barney,则模式会变成/^(fred|barney)/,即在每一行开头寻找fred或barney

捕获变量
--一个圆括号代表一个变量,用$1、$2表示
--失败的匹配模式不会改动上次成功匹配时捕获的内容
$_ = “Hello there, neighbor”;
If (/(\S+) (\S+), (\S+)/) {
  Print “$1 $2 $3”;--打印出Hello there neighbor
}
My $dino = “I fear that I’ll be extinct after 1000 years.”;
If($dino =~ /(\d*) years/) {…}
--不捕获模式,允许使用括号但不作捕捉;书写的时候需要在左括号的后面加上?:(问号和冒号);
If (/(?:bronto)?saurus (steak|burger)/) {—不捕获括号跳过bronto
 Print “Fred wants a $1\n”;
}

命名捕捉
My $names = ‘Fred or Barney’;
If ( $names =~ m/(\w+) and (\w+)/ )—不会匹配
If ($names =~ m/(\w+) (and|or) (\w+)/)—可以匹配
  Say “$1, $2”;--输出Fred or,而Barney进入了$3
--而命名捕捉会把结果放进一个特殊的哈希%+,其中的键就是在捕捉时候使用的特殊标签,值就是被捕获的串;
--为捕获串加标签,(?pattern),其中label可以自行命名;捕获时候使用$+{label}
If ( $names =~ m/(?\w+) (?:and|or) (?\w+)/ ) {
  Say “I saw $+{name1} and $+{name2}”;
}

自动匹配变量
--$&自动捕获当前变量,$`匹配起始位置之前的字符串,$’匹配结束位置之后的字符串;
If (“Hello there, neighbor” =~ /\s(w+),/) {
  Print “That was ($`)($&)($’).\n”;--输出(Hello) ( there,) (neighbor)
}

通用量词
--如果*、+、?都不符合需要,可以在花括号{}里指定重复次数
--/a{5,15}/匹配重复出现5到15次的a
--*等价于{0,};+等价于{1,};?等价于{0,1}


用正则表达式处理文本
用s///替换
$_ = “He’s out with Barney tonight.”;
s/Barney/fred/;--将Barney替换为fred;
替换字符串可以用到捕获变量
s/with (\w+)/against $1’s team/;--变为He’s out against fred’s team
$_ = “green scaly dinosaur”;
s/(\w+) (\w+)/$2, $1/;--替换后变为了scaly, green dinosaur

/g全局替换
--s///只会进行一处替换
--常见的全局替换是缩减空白
$_ = “Input  data\t may     have whitespace.”;
s/\s+/ /g;--现在变为Input data may have whitespace.
--去除开头和结尾的空白
s/^\s+//;--删除开头的空白字符
s/\s+$//;--删除结尾的空白字符

不同的界定符
--s///可以采用不同的定界符
S#^https://#http://#;
S#http://#;

可选修饰符
S#wilma#Wilma#gi—将所有的wilma(不区分大小写)一律替换成Wilma

大小写转换
--替换过程中,将单词改为大写或小写;\U转为大写,\L转为小写;小写的\u\l只会影响第一个字符
$_ = “I saw justin and ren”;
s/(justin|ren)/\U$1/gi;--变为I saw JUSTIN and REN
s/(justin|ren)/\u\L$1/ig;--变为I saw Justin and Ren

split操作符
--根据分隔符拆开一个字符串;
--通常处理被制表符、冒号、空白或任意符号分割的字符串
@fields = split /:/, “:::a:b:c:::”;--得到(””,””,””,”a”,”b”,”c”)
My $some_input = “This is a \t         test.\n”;
My @args = split /\s+/, $some_input;--得到”This”, “is”, “a”, “test.”
--split默认以空白字符分割$_
my @fileds = split;--等同于split /\s+/, $_;

join函数
--将子字符串联合称为一个字符串;可以把第一个参数理解为胶水,其余参数则是一串片段;
My $result = join $glue, @pieces;--列表pieces至少要有两个元素
My @values = split /:/, “4:6:8:10”;--@values为(4,6,8,10)
My $z = join “-“, @values;--$z为4-6-8-10

列表上下文中的m//
--使用m//时,如果模式匹配成功,则返回所有捕获变量的列表;失败则返回空列表;
--如果模式中有多对圆括号,则每次匹配能捕获多个串,可把一个字符串变成哈希
My $data = “Barney Rubble Fred Justin”;
My %last_name = ($data =~ /(\w+)\s+(\w+)/g);--则构造出一对新哈希的键/值对

非贪婪量词
--贪婪量词即保证整体匹配的前提下,尽量匹配长字符串
--非贪婪量词写法+?、*?、??、{8,}?
I thought you said Fred and justin
去除的非贪婪用法
S#(.*?)#$1#g—I thought you said Fred and justin
而s#(.*)#$1#g则会变成I thought you said Fred and justin.

跨行的模式匹配
--/m,匹配串内的换行符
--把整个文件读进一个变量,然后把文件名置于每行的开头:
Open FILE, $filename
  Or die “Can’t open ‘$filename’: $!”;
My $lines = join ‘’, ;
$lines =~ s/^/$filename: /gm;

一次更新多个文件
--备份原文件,将修改过后的内容直接写入新文件;


控制结构
unless
--与if反义,当条件为假时执行

Until
--与while反义,一直循环执行直到条件为真

条件修饰词
--为控制结构的简化表达
Print “$n is a negative number.” If $n < 0;
$i *= 2 until $i > $j;

裸块控制结构
--只执行一次
{
 Body;
}

Foreach和for等价
For (1..10) {…}

循环控制
--perl有三个循环控制操作符
--Last等价于break;跳出当前循环
--Next等价于continue;立刻结束当前迭代,继续执行下次迭代
--Redo将控制返回到本次循环的顶端,不会进入下次循环迭代
for (1..10) {
  print "the $_ times\n";
  print "Please choose: last, next, redo\n";
  chomp(my $choice = );
  #print "\n";
  last if $choice =~ /last/i;
  next if $choice =~ /next/i;
  redo if $choice =~ /redo/i;
  print "now we reach the end of the block\n";
}
运行输出
the 1 times
Please choose: last, next, redo

now we reach the end of the block
the 2 times
Please choose: last, next, redo

now we reach the end of the block
the 3 times
Please choose: last, next, redo

now we reach the end of the block
the 4 times
Please choose: last, next, redo
next
the 5 times
Please choose: last, next, redo
redo
the 5 times
Please choose: last, next, redo
redo
the 5 times
Please choose: last, next, redo
last

带标签的块
--极少出现,建议使用大写
LINE: while (<>) {
 For (split) {
   Last LINE if /__END__/;--跳出标签为LINE的循环
   …
  }
}

三目操作符?:
--同if-then-else同效,条件表达式?真表达式:假表达式;
My $size = ($width < 10) ? “small” :
         ($width < 20) ? “medium” :
         ($width <50) ? “large” : “extra-large”;

“定义否”操作符
--//,
For $try (0,undef,1,) {
  My $value = $try//’default’;
  Say “\tgot [$value]”;--打印出0,default,1,
}


Perl模块
仅选用模块中的部分函数
--模块中的函数和自定义的重名,use File::Basename qw / basename /,不引进任何函数则为use File::Basename qw//;
Use File::Basename qw//;--不导入函数名称
My $betty = &dirname($wilma);
My $dirname = File::Basename::dirname $name;--使用模块中的dirname函数


文件测试
文件测试操作符
--使用”-e”测试文件是否存在
Die “file already exists.\n” if –e $filename;
Warn “Config file is pretty old!\n” if –M CONFIG > 28;--判断文件是否在过去28天里变动过
--查看系统中大于100kB且90天没有被访问过的文件
Push @big_old_files, $filename
  If –s $filename > 100_000 and –A $filename > 90;

同一个文件的多项属性测试
--每次执行文件测试,perl都从文件系统取出所有相关信息(每次都在内部做一次stat操作),比较耗费资源
--采用虚拟句柄_避免重复劳动,告诉perl用上次查询过的文件信息来做当前测试
If ( -r $file and –w _) --

栈式文件测试操作
If ( -r –w –x –o –d $file)—判断可读、可写、可执行、并隶属当前用户的目录

Stat和Istat函数
--获取没有对应测试符的文件属性,如文件拥有者的ID(uid);执行失败返回空列表或包含13个数字元素的列表;
My($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);

Localtime函数
--列表上下文中,localtime返回一个数字元素组成的列表
My($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime $timestamp;


目标操作
在目录树中移动
--程序运行时会以自己的工作目录作为相对路径的起点,使用chdir改变当前的工作目录
Chdir “/etc” or die “cannot chdir to /etc: $!”;--发生错误时会设定标量变量$!的值

文件名通配
--使用glob操作符
My @all_files = glob “*”;--取得当前目录中的所有文件,并按字母顺序排列
My @pm_flies = glob “*.pm”;
--使用尖括号(angle-bracket syntax)进行通配
My @all_files = --等同于@all_files = glob “*”

目录句柄
--从目录里取得文件名列表,-类似文件句柄,opendir/readdir/closedir
--返回的名称列表未按任何特定的顺序排列,只返回文件名,不包括路径
My $dir_to_process = “/etc/”;
Opendir DH, $dir_to_process or die “cannot open $dir_to_process: $!”;
While ($name = readdir DH) {
  Next unless $name =~ /\.pm$/;--查询以.pm结尾的文件
  Next if $name =~ /^\./;--查询不以点号开头的文件
  …
}

递归的目录列表
--使用File::Find

删除文件
--使用unlink删除
Unlink glob “*.O”;--等价于rm *.O
My $successful = unlink “slate”,”bedrock”,”lava”;--返回删除文件的个数
--删除文件的权限跟文件本身的权限位无关,取决于文件所在目录的权限位

重命名文件
--rename “old”,”new”;
批量将.old结尾的文件改为.new
Foreach my $file (glob “*.old”) {
  My $newfile = $file
  $newfile =~  s/\.old$/.new/;
  If (-e $newfile) {
Warn “$newfile already exists.\n”;
  } elsif( rename $file, $newfile) {
--改名成功
  } else {
Warn “rename failed: $!\n”
  }
}
循环里的前两行可以合并成
(my $newfile = $file) =~ s/\.old$/.new/;--声明$newline并从$file里取它的初始值,然后对$newfile进行替换;

链接与文件
--取得符号链接指向的位置readlink
My $where = readlink “carroll”;

建立及删除目录
--oct函数,强行把字符串当成八进制数字处理
My $permissions = “0755”;
My $name = “fred”;
Mkdir $name, oct($permissions);
Rmdir $name;

修改权限
Chmod 0755, “fred”, “barney”—返回成功更改的条目数量

更改隶属关系
--使用chown,更改拥有者和所属组,必须以数字形式指定;如果是字符串则需要先用getgrnam转换为数字
Defined(my $user = getpwnam “oracle”) or die “bad user”;
Defined(my $group = getgrnam “oinstall”) or die “bad group”;
Chown $user, $group, glob “/home/oracle/*”;

更改时间戳
--utime 访问时间 更改时间 文件名列表
My $now = time;
My $ago = $now ? 24*60*60;--一天的秒数
Utime $now, $ago, glob “*”;--将最后访问时间改为当前时间,修改时间改为前一天


字符串与排序
字符串内用index搜索
--$where = index($big, $small);在$big字符串里寻找$small首次出现的地方,最开始的位置返回0
My $where2 = index($stuff, “w”, $where1 + 1);
--rindex搜索子串最后出现的位置
My $last_slash = rindex(“/etc/passwd”,”/”);--值为4

Substr处理子串
--$part = substr($string,$initial_position,$length)

Sprintf格式化数据
--唯一与printf不同之处,返回处理过的字符串,而不是打印出来

高级排序
--by_number { $a <=> $b} 等价于 { if ($a < $b) { -1 } elsif ($a > $b) {1} else {0} }
--飞碟操作符只能比较数值 <=>
--cmp可以比较字符串,{$a cmp $b};比较之前强制转为小写{“\L$a” cmp “\L$b”}

My @numbers = sort { $a <=> $b } @some_numbers;--递增排序
My @numbers = reverse sort { $a <=> $b } @some_numbers;--递减排序

哈希按值排序



智能匹配
智能匹配操作符~~
--类似=~,但更智能
--在哈希%names中查找任何匹配Fred的键
Foreach my $key (keys %names) {
  Next unless $key =~ /Fred/;
  $flag = $key;
  Last;
}
可以改写成
Say “I found a key matching ‘Fred’” if %names ~~ /Fred/;
--智能匹配看到哈希和正则表达式,会知道该遍历%names的所有键,用给定的正则表达式逐个测试

比较两个数组(简单起见,只考虑等长数组)
Foreach my $index ( 0 .. $#names1 ){
  Last unless $names[$index] eq $name2[$index];
  $equal++;
}
Print “The arrays have the same elements!\n” if $equal == @names1;
--智能匹配改写 say “The arrays have the same elements!” if @names1 ~~ @names2;

%a ~~ %b—哈希的键是否一致
%a ~~ @b—至少%a中的一个键在列表@b之中
%a ~~ /Fred/--至少一个键匹配给定的模式
%a ~~ ‘Fred’—哈希中某一指定键$a[Fred]是否存在
@a ~~ /Fred/--有一个元素匹配给定的模式
@b ~~ ‘Fred’—至少有一个元素转化为字符串后是’Fred’

Give-when匹配
--与if-elsif-else相比,可以在满足某个条件的基础上继续测试其他条件
Given( $ARGV[0] ) {
  When( /fred/i ) {say ‘name has fred in it; continue}
  When( /^Fred/ ) {say ‘name starts with Fred’; continue}
  When( ‘Fred’ ) { say ‘name is Fred’ }
  Default { say “ I don’t see a Fred’}
}



进程管理
System函数
--调用unix、shell命令
System “date”;--输出当前时间
--利用shell启用后台进程
System “long_running_command with parameters &”;--启动shell,&会让long_running_command成为后台进程并立即运行,而perl接到shell的返回值会继续执行下一步
System ‘for I in *;do echo == $i ==; cat $i; done;’;--列出当前目录下所有文件名及其内容

避免使用shell
--system调用一个以上的参数,将不会用到shell
--unix中运行成功返回0,
!system “rm –rf files_to_delete” or die “something went wrong”;

Exec函数
--与system区别:system会闯进子进程,其在perl睡眠期间执行任务;而exec却导致perl自己去执行任务
--一旦启动要执行的程序,perl便放手退出,因此exec之后写的任何代码都无法运行,除非是编程接管启动过程中的错误,如die

用反引号捕获输出结果
--system/exec调用程序的输出都会定向到perl的标准输出,可以用反引号捕获输出的字符串
Chomp(my $no_newline_now = `date`);
--类似于system的单参数形式,但不需要捕获输出的时候,最好不要使用反引号

在列表上下文中使用反引号
--标量上下文 my $who_text = `who`;--就一行
--列表上下文 my @who_lines = `who`;--会自动拆成多行
Foreach (`who`) {
  My($user,$tty,$date) = /(\S+) \s+ (\S+) \s+ (.*)/;
  $ttys{$user} .= “$tty at $date\n”;
}


将进程视为文件句柄
--perl可以启动一个异步运行的子进程,并和它保持通信,直到子进程结束
Open DATE, “date | “ or die “cannot pipe from date: $!”;
竖线在命令右边,表示执行时它的输出会转向只读的文件句柄DATE,就像shell的date | your_programm
Open MAIL, “| mail Merlyn” or die “cannot pipe to mail: $!”;
竖线在命令左边,类似shell的your_mail | mail Merlyn
Open F, “find / -atime +90 –size +1000 –print | “ or die “fork: $!”;
While () {
  Chomp;
  Printf “%s size %dk last accessed on %s\n”, $_, (1023 + -s $_)/1024, -A $_;
}
--查找90天内未被存取过的1000块以上的大文件,find工作时,perl会等待;
每找到一个文件,perl立即收到文件名并进一步分析;如果用反引号则必须等待find彻底搜完后才能有第一行输出

用fork开展地下工作
--同样的system “data”,可以改写为如下
Defined(my $pid= fork) or die “cannot fork: $!”;
Unless ($pid) {
  #能运行到这里的是子进程
  Exec “date”;
  Die “cannot exec date: $!”;
}
#能运行到这里的是父进程
Waitpid($pid,0);

发送及接受信号
--从perl发送信号给别的进程,需要先获取目标进程的编号
Kill 2, 4201 or die “Cannot signal 4201 with SIGINT: S!”;
--发送信号的命令取名kill,2就是SIGINT;如果该进程早已退出,会收到返回的错误
Unless (kill 0, $pid) { warn “$pid has gone away!”; }
--程序运行时候创建文件夹,正常处理会删除,为防止运行时被终止而导致文件夹不能删除,可运用信号量
Mkdir $temp_dir, 0700 or die “Cannot create $temp_dir: $!”;
Sub clean_up {
  Unlink glob “$temp_dir/*”;
  Rmdir $temp_dir;
}
Sub my_int_handler {
  &clean_up;
  Die “interrupted, exiting…\n”;
}
$SIG(‘INT’) = ‘my_int_handler’;
--对特殊哈希%SIG赋值,哈希键是信号名称(不用写固定前缀SIG);哈希值是子程序名,不需要”&”;只要收到SIGINT信号,perl就会暂停手上事务立刻执行信号处理子程序
&clean_up;
--下面这个例子是当ctrl+c的时候中断当前执行而非退出程序;如果没有ctrl+c,则程序继续下一次处理;否则终止循环
My $int_count;
Sub my_int_handler { $int_count++ };
$SIG(‘INT’) = ‘my_int_handler’;
$int_count = 0;
While () {
  …..—一些耗时操作
  If ($int_count) {
Last;
  }
}


高级perl技巧
用eval捕获错误
--一些如除以0等错误如不加处理会让程序崩溃
Eval { $result = $a / $b };
--运行eval后查看$@变量,如果为空证明执行成功;否则会报出错误信息;类似pl/sql中的exception捕获
Foreach my $person (qw/ fred justin /) {
  Eval {
    Open FILE, “< $persion” or die “Cannot open file ‘$person’: $!”;
--无法打开文件导致错误
--其他潜在错误
};
  If ($@) {
Print “An error occurred ($@)\n”;
  }
}
--eval无法捕获的错误:1、让perl解释器崩溃的严重错误,如内存不足;2、exit操作符;3、语法错误;4、warn警告信息
--使用eval字符串的时候要小心安全漏洞

用grep筛选列表
--从一大堆数字中删除奇数
Foreach (1..1000) {
  Push @odd_numbers, $_ if $_ % 2;
}
--可以使用grep简化如下:第一个参数是代码块,代码块对后面列表中的每个元素计算
My @odd_numbers = grep { $_ % 2} 1..1000;
--从一个文件中过滤包含了fred的行
My @matching_lines = grep { /\bfred\b/I } ;

切片
--文件格式为name:id:address:phone
While () {
  Chomp;
  My @items = split /:/;
  My($name,$phone) = ($item[0],$item[3]);
}
数组@items只是充当临时变量,可以取消
My($name,$id,$address,$phone) = split /:/;
但是标量$id,$address又是不必要的,可以写成
My ($name,undef,undef,$phone) = split /:/;
如果参数个数过多则容易弄错,此时可以使用列表切片
My($name,$phone) =(split /:/)[0,3];
-1代表最后一个元素
My($first,$last) = (sort @names)[0,-1]—排序后数组的第一个和最后一个元素
My $mtime = (stat $some_$file)[9]—mtime是stat产生列表的第9个元素,stat周围的括号是必须的

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15480802/viewspace-703261/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/15480802/viewspace-703261/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值