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