如何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周围的括号是必须的
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/15480802/viewspace-703261/
,如需转载,请注明出处,否则将追究法律责任。