perl有个技巧,将两个"!"一块儿用,至关于"负负得正",因此原来是真的仍然是真的,原来是假的仍然是假的。但实际上,perl会将它们转换值"1"和"undef"。php
$still_true = !!"fred"; # $still_true的值是1 $still_false1 = !!"0"; # $still_false1的值为空(undef) $still_false2 = !!""; # $still_false2的值为空(undef) print "$still_true"."\n"; print "$still_false1"."\n"; print "$still_false2"."\n";
它们都是条件判断语句,都支持else、elsif子句。html
if(CONDITION){ # 或者 unless(CONDITION) command } if(CONDITION1){ # 或者 unless(CONDITION1) command1 }elsif(CONDITION2){ command2 }elsif(CONDITION3){ command3 } ... else{ commandN } if(CONDITION){ # 或者 unless(CONDITION) command1 }else{ command2 }
其中CONDITION能够是任意一个标量值。布尔值的判断很简单,方式和bash shell有点相似,但有点相反。python
unless和if判断方式相反,if的condition为真则执行后面的代码,不然执行else或者退出if结构。unless则是condition为假时才执行后面的代码,不然执行else或退出unless结构。因此,unless至关于if的else部分,或者至关于if (!condition)
。shell
通常来讲,不会用到unless的else语句,由于它彻底能够改编成if语句。之因此有时候会使用unless而不是if的否认形式,是由于有时候的条件语句用if来写确实不方便。express
?:
perl也支持三目运算符:若是expression返回真,则整个表达式返回if_true
,不然返回if_false
数组
expression ? if_true : if_false
例如,求平均值,若是$n=0,则输出"------"。bash
$avg = $n ? $sum/$n : "------";
它等价于:less
if($n){ $avg = $sum / $n; }else{ $avg = "------"; }
三目运算符能够写出更复杂的分支:ide
#!/usr/bin/perl # use 5.010; $score = $ARGV[0]; $mark = ($score < 60) ? "a" : ($score < 80) ? "b" : ($score < 90) ? "c" : "d"; # 默认值 say $mark;
执行结果:函数
$ perl test.plx a $ perl test.plx 33 a $ perl test.plx 63 b $ perl test.plx 83 c $ perl test.plx 93 d
expr1 < and or && || // > expr2 <not !>expr
&&
运算符只有两边为真时才返回真,且短路计算:expr1为假时直接返回false,不会评估expr2||
运算符只要一边为真时就返回真,且短路计算:expr1为真时直接返回true,不会评估expr2and
和or
基本等价于对应的&&
和||
,但文字格式的逻辑运算符优先级很是低not
和!
求反,一样文字格式的not
的优先级很低//
运算符见下文if (($n >=60) && ($n <80)){ print "..."; } if ($n >=60 and $n <80){ print "..."; }
or
运算符每每用于链接两个"成功执行,不然就"的子句。例如,打开文件,若是打开失败,就结束该perl程序:
open LOG '<' "/tmp/a.log" or die "Can't open file!";
更常见的,还会分行缩进:
open LOG '<' "/tmp/a.log" or die "Can't open file!";
一样,and
运算符也经常使用于链接两个行为:左边为真,就执行右边的操做(例如赋值)。
$m < $n and $m = $n; # 以$m的姿态取出$m和$n之间较大值
如下是3个语句是等价语句:
if ($m<$n){$m=$n} $m=$n if $m<$n; $m=($m < $n) ? $n : $m;
//
perl的短路计算很是特别,它返回的是最后运算的表达式的值:
这个返回值有时候颇有用,每每经过逻辑或的操做来设置默认值,因此,这个返回值既保证短路计算的结果不改变,又能获得返回值。
例如
my $name = $myname || "malongshuai"
当$myname
变量存在时,它返回真(0是例外,见下面),并将$myname
赋值给$name
;当$myname
变量不存在时,它返回假,因而评估"malongshuai",由于是个字符串,因此返回真,因而将malongshuai
赋值给$name
。这样一来,$myname
变量就有了默认值。
可是,若是$myname
变量存在,但值为0(字符串的或数值的),因为它也返回假,致使$name
被赋以"malongshuai"。
这种行为显然并不是咱们所须要的。因而,改用下面这种先判断,再赋值的行为:
my $name = defined($myname) ? $myname : "malongshuai";
可是这样的写法比较复杂,perl 5.10版本提供了更方便的"逻辑定义或"(logical defined-or)操做符//
:当发现左边的值是已经定义过的,就直接进行短路计算,而无论该左边的值评估后是真是假。
use 5.010; my $name = $myname // "malongshuai";
这个操做符应对开启了use warnings
功能的perl程序颇有用,省得warnings发出烦人的警告。
while(CONDITION){ commands; } until(CONDITION){ commands; }
until和其它某些语言的until循环有所不一样,perl的until循环,内部的commands主体可能一次也不会执行,由于Perl会先进行条件判断,当条件为假时就执行,若是第一次判断就为真,则直接退出until。
Perl中的for循环采起C语言的for风格,例如:
for($i=1;$i<=10;$i++){ print $i,"\n"; } print $i,"\n"; # 输出11
须要注意的是,上面的$i
默认是全局变量,循环结束后还有效。可使用my关键字将其声明为局部变量:
for (my $i = 1;$i<=10;$i++ ){ print $i,"\n"; }
for循环不只仅只支持数值递增、递减的循环方式,还支持其它类型的循环,只要能进行判断便可。见下面的例子。
for关键字后面括号中的3个表达式均可以省略,但两个分号不能省略:
例如,下面分别省略第三个表达式和省略全部表达式:
for(my $str="malongshuai";$str =~ s/(.)//;){ print $str,"\n"; } for(;;){ print "never stop"; }
对于无限循环,Perl中更好更优化的方式是使用:
while(1){ command; }
Perl中的for也支持成员测试性的遍历,就像shell中的for i in ...
的操做同样,它期待一个列表上下文,表示遍历整个列表。若是省略控制变量,表示使用$_
。例如:
my @arr = qw(Shell Python Perl PHP); for $i (@arr){ print "$i\n" } for (@arr) {print "$_\n"}
像for遍历列表元素的操做,可使用foreach来替代,大多数迭代列表的时候它们能够互换。
(由于还没介绍数组和hash,因此这里能看懂就看,不能看懂等到介绍数组的时候再看里面的foreach示例)
foreach更适合用于遍历,全部foreach都能直接修改关键字为for而转换成for循环。当写成for格式的时候,perl经过判断括号中的分号来决定这是foreach循环仍是for的普通循环。但for能实现的循环功能,foreach不必定能实现,由于for中有初始变量,有条件判断,而foreach则是简单版的for循环。
先解释下foreach的用法:
例如,迭代从1到10的列表:
foreach $i (1..10){ print $i,"\n"; }
其中$i
称为控制变量,每迭代一次都会从迭代列表中取出一个元素赋值给控制变量。能够省略控制变量,这时将采用默认的变量$_
:
foreach (1..10){ print $_,"\n"; }
foreach能够改写为for:
for(1..10){ print $_,"\n"; } for ($i=1;$i<=10;$i++){ print $i,"\n"; } @arr=qw(malongshuai gaoxiaofang xiaofang longshuai wugui fairy); for (@arr){ print $_,"\n"; }
关于for循环和foreach循环,若是在遍历过程当中修改了元素的值,它会直接修改原始值。换句话说,迭代时赋值给控制变量的元素的引用,而不是赋值元素再赋值给控制变量。
@arr=qw(perl python shell); foreach $subject (@arr) { $subject .= "aaa"; } print @arr; # 输出perlaaapythonaaashellaaa
当foreach/for遍历结束后,控制变量将复原为foreach/for遍历前的值(例如未定义的是undef)。
$subject="php"; foreach $subject (qw(perl python shell)){ } print $subject; # 输出"php"
each HASH each ARRAY
each用来遍历hash或数组,每次迭代的过程当中,都获取hash的key和value,数组的index(数值,从0开始)和元素值。
each放在列表上下文,会返回key/value或index/element,放在标量上下文则只返回key或index。
遍历hash:
#!/usr/bin/perl -w use strict; my %hash = ( name1 => "longshuai", name2 => "wugui", name3 => "xiaofang", name4 => "woniu", ); while(my($key,$value) = each %hash){ print "$key => $value\n"; }
输出结果:
name4 => woniu name3 => xiaofang name2 => wugui name1 => longshuai
遍历数组:
#!/usr/bin/perl -w use strict; my @arr = qw(Perl Shell Python PHP Ruby Rust); while(my($key,$value) = each @arr){ print "$key => $value\n"; }
输出结果:
0 => Perl 1 => Shell 2 => Python 3 => PHP 4 => Ruby 5 => Rust
each放在标量上下文:
#!/usr/bin/perl -w use strict; my %hash = ( name1 => "longshuai", name2 => "wugui", name3 => "xiaofang", name4 => "woniu", ); my @arr = qw(Perl Shell Python PHP Ruby Rust); while(my($key) = each %hash){ print "$key\n"; } while(my($key) = each @arr){ print "$key\n"; }
输出结果:
name2 name4 name3 name1 0 1 2 3 4 5
perl支持单条表达式后面加流程控制符。以下:
command OPERATOR CONDITION;
例如:
print "true.\n" if $m > $n; print "true.\n" unless $m > $n; print "true.\n" while $m > $n; print "true.\n" until $m > $n; print "$_" foreach @arr;
不少时候会分行并缩进控制符:
print "true.\n" # 注意没有分号结尾 if $m > $n;
改写的方式几个注意点:
$_
print "abc",($n += 2) while $n < 10;
print "abc",($n += 2) until $n > 10;
使用大括号包围一段语句,这些语句就属于这个语句块,这个语句块实际上是一个循环块结构,只不过它只循环一次。语句块也有本身的范围,例如能够将变量定义为局部变量。
{ print "Enter a Num","\n"; chomp(my $n = <STDIN>); $res = sqrt $n; print "$res","\n"; } print $res,"\n";
use 5.010; use strict; foreach (1..10){ say "startline...: $_"; say "enter a word: last, next, redo?"; chomp(my $choice = <STDIN>); last if $choice =~ /last/i; next if $choice =~ /next/i; redo if $choice =~ /redo/i; say "endline...: $_"; } say "outside loop...";
如下是打标签的示例(标签建议采用大写):
/usr/bin/perl use 5.010; use strict; LINE: while(<>){ foreach(split){ last LINE if /error/i; say "$_"; } }
上面的标签循环中,首先读取一行输入,而后进入foreach遍历,由于split没有参数,因此使用默认参数$_
,这个$_
所属范围是while循环,split以空格做为分隔符分割这一行,同时foreach也没有控制变量,因此使用默认的控制变量$_
,这个$_
所属范围是foreach循环。当foreach的$_
能匹配字符串"error"则直接退出while循环,而不只仅是本身的foreach循环。这里if语句后采用的匹配目标是属于foreach的默认变量$_
。
例如,这个perl程序读取a.txt文件,其中a.txt文件的内容以下:
$ cat a.txt hello world hello world Error hello world Error heihei
执行这个perl程序:
$ perl -w test.plx a.txt hello world hello world
可见,只输出了a.txt中第二行Error前的4个单词。
perl中还有一个continue关键字(http://perldoc.perl.org/functions/continue.html),它能够是一个函数,也能够跟一个代码块。
continue # continue函数 continue BLOCK # continue代码块
若是指定了BLOCK,continue可用于while和foreach以后,表示附加在循环结构上的代码块。
while(){ code }continue{ attached code } foreach () { code } continue { attached code }
每次循环中都会执行此代码块,执行完后进入下一循环。
在continue代码块内部,也可使用redo、last和next控制关键字。因此,这几个流程控制关键字更细致一点的做用是:redo、last直接控制循环主体,而next是控制continue代码块。因此:
while(){ # redo jump to here CODE } continue { # next jump to here CODE # next loop } # last jump to here
实际上,while和foreach在没有给定continue的时候,逻辑上等价于给了一个空的代码块,这时next能够跳转到空代码而进入下一轮循环。
例如:
#!/usr/bin/env perl use strict; use warnings; $a=3; while($a<10){ if($a<6){ print '$a in main if block: ',$a,"\n"; next; } } continue { print '$a in continue block: ',$a,"\n"; $a++; }
输出结果:
$a in main if block: 3 $a in continue block: 3 $a in main if block: 4 $a in continue block: 4 $a in main if block: 5 $a in continue block: 5 $a in continue block: 6 $a in continue block: 7 $a in continue block: 8 $a in continue block: 9