您的位置:首页 > 其它

perl入门学习笔记

2015-07-28 10:30 330 查看
如何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<^https://>#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周围的括号是必须的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: