我的評價:本書是perl的經(jīng)典入門書籍,介紹了perl中最基本的概念和語法,是perl入門的好書,我向所有想了解或?qū)W習(xí)perl語言的朋友推薦本書。書中穿插有perl語法形成的歷史和原因,使你能充分感受到perl語言的文化,這也是perl流行的原動力。本書行文流暢,各知識點介紹到位,令人很容易明白,達(dá)到入門點睛的效果。但本書的作用也就是入門而已,目的很明確,它沒有深入到perl腳本語言的高級部份。如果你想了解perl的高級功能或使用perl來更好地完成你的日常工作,還需進(jìn)一步學(xué)習(xí),《perl語言編程》應(yīng)該是你最好的選擇。第一章 簡介第二章 標(biāo)量數(shù)據(jù)什么是標(biāo)量數(shù)據(jù)?標(biāo)量(scalar)是perl中最基本的元素。大多數(shù)標(biāo)量要么是一個數(shù)字,要么是一個字符串。perl基本上把它們視為可相互替換的東西。數(shù)字所有數(shù)字的內(nèi)部格式都一樣在內(nèi)部,perl一律把整數(shù),浮點數(shù)按雙精度浮點數(shù)進(jìn)行計算。perl內(nèi)部沒有整數(shù)值----程序中的一個整數(shù)常量被當(dāng)作等值的浮點數(shù)。直接量(literal)指的是在perl源代碼中表示值的方式,浮點直接量 1.33,233.5,-3.9整數(shù)據(jù)直接量 0,89,-66,61_383_883_897_363(一個大數(shù),用下劃線以示清晰)非十進(jìn)制整數(shù)直接量八進(jìn)制直接量以0開頭十六進(jìn)制直接量以0x開頭二進(jìn)制以0b開頭從5.6版本開始,perl允許在直接量中加下劃線以示清晰。0x50_65_7c數(shù)值操作符加 + 2 + 3減 - 3 - 2乘 * 2 * 3除 / 2/3模 % 10%3指數(shù) ** 2**3字符串單引號字符串直接量 在引號間除了單引號或反斜杠以外的任何字符(包括換行符,如果該字符串連續(xù)占幾行)在字符串中表示該字符本身。要想得到一個斜杠,需要連續(xù)寫兩個斜杠,要得到一個單引號,需要加一個斜杠。雙引號字符串直接量 在雙引號內(nèi)的反斜杠開始發(fā)揮它的作用,可以用來指定特定的控制字符??梢栽陔p引號里面內(nèi)插變量。雙引號內(nèi)的轉(zhuǎn)義字符完整列表\n 換行\(zhòng)r 回車\t 制表符\f 換頁\b 退格\a 響鈴\e Esc(ascii的轉(zhuǎn)義字符)\007 任意ASCII碼的八進(jìn)制值(這里007=響鈴)\x7f 任意ASCII碼的十六進(jìn)制值(這里07f=刪除)\cC 任意Ctrl鍵組合字符(這里是Ctrl-C)\\ 反斜杠\" 雙引號\l 下一個字母小寫\L 所有后面的字母小寫,直到\E\u 下一個字母大寫\U 所有后面的字母大寫,直到\E\Q 添加反斜杠引用后面的非單詞字符,直到\E\E 結(jié)束\L,\U,\Q字符串操作符. 連接兩個字符串 "hello" . "world" = "helloworld"x 串重復(fù)操作符 "yang" x 3="yangyangyang" 次數(shù)使用前截成一個整數(shù)。4.8=4,小于1的拷貝次數(shù)會得到一個空串。數(shù)字與字符串的自動轉(zhuǎn)換依賴于作用在標(biāo)量值上的操作符。如果是+則是數(shù)據(jù),如果是.則是字符串。"z".6*7="z42" ,"12"*"3"=36perl的內(nèi)置警告可以要求perl在發(fā)現(xiàn)你程序有異常時給你一個警告。使用 -w 選項。#!/usr/bin/perl -w標(biāo)量變量變量(variable)是一個容器的名字,用以存放一個或多個值,變量的名字在程序中保護(hù)不變,但它所包含的值在執(zhí)行過程中一般要不停地改變。在perl中用美元符號標(biāo)識。$a,$test。選擇好的變量名適當(dāng)加一些下劃線可讓變量更易讀,更易理解。標(biāo)量賦值(assignment)操作符用等號,它的左邊是變量名,右邊是值。二元賦值操作符+= -= *= .= **= and so on用print輸出print "hello world\n";print "the answer",6*6,".\n";在字符串中替換標(biāo)量變量$meal = "brontosaurus steak";$barney = "fred ate a $meal"; 另一種寫法 $barney = ‘fred ate a‘.$meal;如果標(biāo)量變量從未被賦過值,就用一個空串替換。操作符優(yōu)先級和結(jié)合性善用小括號perlk中的操作符優(yōu)先級和結(jié)合性與C一樣比較操作符相等 == eq不相等 != ne小于 < lt大于 > gt小于等于 <= le大于等于 >= geif控制結(jié)構(gòu)if () {...;} else {...;}布爾值perl中沒有單獨的的布爾數(shù)據(jù)類型,不過,它使用幾條簡單的規(guī)則。1、特殊值undef是假。2、0是假,所有其它的數(shù)字是真。3、空串‘‘是假,所有其它的字符串一般是真。4、一個例外,因為數(shù)字和字符是等價的,所以0的字符形式‘0‘,和它的數(shù)值形式有同樣的值:假。! 是取反的意思,可以在真值前加,結(jié)果就變成了假。取得用戶輸入<STDIN>從鍵盤得到一個值。一般以\n字符結(jié)束。所以可利用該字符做條件控制。chomp操作符它作用于一個變量,此變量必須存放一個字符串,如果這個字符串以換行符結(jié)尾,chomp就把它去掉。$text = "a line of text\n";chomp ($text); 去掉換行符chomp($text =<STDIN>); 最常用的方法,讀文本,不帶換行符chomp是一個函數(shù),所有它有返回值,即去掉的字符個數(shù)。使用chomp時可以帶或不帶小括號,這是perl的另一個基本規(guī)則,除非去掉括號會改變意思,否則括號總是可有可無的。while控制結(jié)構(gòu)重復(fù)執(zhí)行一個代碼塊,只要條件為真。$count = 0;while ($count < 10 ) {$count +=1;print "count is now $count\n"; 得到從1到10的值。}undef值變量在第一次賦值之前有特別的undef值,代表什么也沒有。當(dāng)把它作為字符串時,其功能相當(dāng)于一個空串。當(dāng)把它作為數(shù)字時,其功能相當(dāng)于0。perl程序員經(jīng)常這樣使用。很多操作符在操作數(shù)超出范圍或沒有意義時會返回undef值,這樣一般不是什么問題,但如果打開perl的警告,則會導(dǎo)至一個警告。defined函數(shù)測試一個值是undef還是非空字符串,可以使用這個函數(shù)。它對undef返回假,其它所有情況則返回真:$madon = <STDIN>;if (defined($madon) {print "the input was $madon";} else {print "no input available!\n";}如果你想生成自已的undef值,可以用古怪的undef操作符$madon = undef; 好像它從來沒有被動過第三章 列表和數(shù)組在perl中,如果“單數(shù)”是標(biāo)量,那么“復(fù)數(shù)”則由列表和數(shù)組來表示。列表(list)是一個有序的標(biāo)量集合,數(shù)組(array)是一個包含列表的變量。精確地說,列表是數(shù)據(jù),而數(shù)組是變量,可以有一個不在數(shù)組的列表,但每個數(shù)組變量都包含一個列表。數(shù)組和列表可以放任意多的元素,最小的是沒有元素,而最大的可以把所有內(nèi)存耗盡。這符合perl的“沒有不必要的限制”哲學(xué)。訪問數(shù)組的元素數(shù)組元素用連續(xù)的整數(shù)編號,從0開始,然后按1遞增。$fred[0] = "a";$fred[1] = "b";$fred[2] = "c";如果下標(biāo)所指的元素超出了數(shù)組的區(qū)間,那么相應(yīng)的值就是undef。特殊的數(shù)組索引如果你試圖存儲一個超出數(shù)組區(qū)間的數(shù)組元素,這個數(shù)組就會自動按需擴展,對它的長度沒有限制,只要有足夠的內(nèi)存供perl使用。$rocks[0] = "a";$rocks[1] = "b";$rocks[2] = "c";$rocks[10] = "end"; 現(xiàn)在就有6個undef元素。訪問最后一個元素的索引是$#rocks。負(fù)的數(shù)組索引從數(shù)組尾部算起,-1代表最后個元素。列表直接量列表直接量(list literal)是小括號中的一列由逗號分隔的值。例如:(1,2,3,4) (“fred”,43.4) () (1..100) (0..$#rocks)“..”是區(qū)間操作符,能生成一個順序列表。如上例中的從1到100。列表可包含表達(dá)式或變量。qw快捷方式qw表示“被括引的單詞”(quoted words)或“用空白括住”(quoted by whitespace),perl按單引號字符串處理它們,所以你不能像在雙引號字符串中那樣在qw列表中用\n或$fred)。qw /a b c d/ 等同于 ("a","b","c","d")qw !a b c d! 等同于 ("a","b","c","d")qw {a b c d} 等同于 ("a","b","c","d")定界符可以選擇任意的標(biāo)點。列表賦值($fred,$barney,$dino) = ("a","b","c")($fred,$barney) = ($barney,$fred) 交換它們的值,比c等語言方便很多。如果變量的個數(shù)小于值的個數(shù),則多余的值會被無聲地忽略。如果變量的個數(shù)多于值的個數(shù),則多的變量會得到undef值。at符號@可以一次指定整個數(shù)組。這樣@rocks代表“所有的rocks”。@rocks = qw / a b c/;@copy = @quarry 從一個數(shù)組拷貝一個列表到另一個數(shù)組pop and push操作符正真的perl程序員不使用索引訪問數(shù)組,這樣發(fā)揮不了perl的強項。我們經(jīng)常把數(shù)組當(dāng)信息棧用??偸菑牧斜淼挠覀?cè)加入新值或刪除。pop操作取出一個數(shù)組的最后一個元素@array = 5..9;$fred = pop(@array); $fred得到9,@array現(xiàn)在有(5,6,7,8)$barney = pop(@array); $barney得到8,@array現(xiàn)在有(5,6,7)如果數(shù)組是空的,pop就不管它,因為沒有元素可刪除,只返回undef。push操作與pop對應(yīng),它順數(shù)組的最后添加一個元素或一個元素列表。push(@array,0); @array現(xiàn)在有(5,6,7,0)@others = qw /1 2 3/;push @array,@others @array現(xiàn)在有(5,6,7,0,1,2,3)注意:push的第一個參數(shù)或pop的唯一參數(shù)必須是一個數(shù)組變量,進(jìn)棧和出棧對直接量列表來說是沒有意義的。shift and unshift 操作類似于push and pop,shift and unshift對數(shù)組的頭部進(jìn)行相應(yīng)的操作。在字符串中替換數(shù)組與標(biāo)量一樣,數(shù)組的值也可以被替換到雙引號字符串中。print "quartz @rocks limestone\n"; 打印所有巖石,用空格分開。注意:不要把電子郵件地址放到雙引號字符串中。foreach控制結(jié)構(gòu)foreach循環(huán)遍歷列表中的所有值,對每個值執(zhí)行一個迭代(執(zhí)行一次循環(huán)體)foreach $rocks ( qw /a b c/) {print "one rock is $rocks.\n"; 打印a b c。}Perl最喜歡的缺省變量:$_如果你在foreach循環(huán)的開始忽略了控制變量,perl就會使用$_。foreach (1..10) { 缺省使用$_print "I can count to $_!\n";}$_ = "a";print; 缺省打印$_reverse操作符reverse 取一個列表的值,然后返回相反順序的列表。記住它只返回反序列表,并不影響它的參數(shù),如果返回值不被賦給別的變量,它是不保存。sort操作符sort取一個列表的值,然后按照內(nèi)部字符序進(jìn)行排序。標(biāo)量和列表上下文一個給定的表達(dá)式在不同的地方,可能會有不同的含義。5 + something something必須是個標(biāo)量sort something something必須是個列表在標(biāo)量上下文中使用列表生成表達(dá)式提供標(biāo)量上下文的表達(dá)式:$fred = something;$fred[3] = something;123 + somethingsomething +654;if (something) {...}while (something) {...}$fred[something] = something;提供列表上下文的表達(dá)式:@fred = something;($fred,$barney) = something;($fred) = something;push @fred,something;foreach $fred (something) {...}sort something;reverse something;print something;在列表上下文中使用標(biāo)量生成表達(dá)式如果一個表達(dá)式在正常情況下不生成一個列表值,那么自然它就會生成標(biāo)量值,即一個元素列表:@fred = 6*7 得到一個單元素列表(42)注意,因為undef是個村標(biāo)量值,所以給一個數(shù)組賦undef并不能清空數(shù)組,清空的更好方法是賦一個空列表()。強制使用標(biāo)量上下文可以使用scalar假函數(shù),它告訴perl提供一個標(biāo)量上下文。@rocks = qw /a b c d/;print "i have",@rocks,"rocks!\n"; 錯,打印了石頭的名字print "i have",scalar @rocks,"rocks!\n"; 正確,打印石頭的數(shù)量列表上下文中的<STDIN>chomp (@lines = <STDIN>); 讀入那些行,不帶換行符第四章 子例程系統(tǒng)與用戶函數(shù)perl的子例程可以讓我們在一個程序中重復(fù)利用一塊代碼,子例程名字是在前面加一個可有可無的&符號,有一條規(guī)則規(guī)定什么時候可以省略。定義一個子例程使用關(guān)鍵字sub和子例程名定義??梢苑旁诔绦虻娜魏挝恢?。sub marine {$n += 1;print "hello ,sailor number $n!\n";}注意:n 為全局變量調(diào)用子例程$marine; 輸出hello,sailor number 1!$marine; 輸出hello,sailor number 2!返回值每個子例程在運行過程中,計算值是它一系列動作的一部份。在子例程中得到的最后一個計算值自動成為返回值。因此注意在向子例程增加代碼時要確保最后一個表達(dá)式的結(jié)果是你希望的返回值?!白詈笠粋€表達(dá)式”是指真正的、被最后計算的表達(dá)式,而不是正文的最后一行。參數(shù)參數(shù)列表在子例程運行期間被自動地賦給一個特別的數(shù)組變量@_。子例程可以訪問這個變量以確定參數(shù)個數(shù)和參數(shù)的值。也就是說,第一個參數(shù)被存在@_[0],第二個被存在@_[1]中,其它依次類推。@_變量是子例程的局部變量,如果@_中有一個全局變量,它就會在子例程調(diào)用前被保存起來,而在子例程返回時恢復(fù)原值。子例程中的私有變量my操作符生成被稱為詞法變量(lexical variable)的私有變量。local操作符local的真正功能是把給定的變量的一個拷貝保存在一個秘密的地方(棧)。這個值在保存后不能被訪問、修改、刪除,讀出、檢查、打印等。在perl中沒有辦法以接近被保存的值。接著local把該變量設(shè)為空值(對標(biāo)量是undef,對數(shù)組是空表),或設(shè)為任何賦給它的值。當(dāng)perl從子例程中返回時,會自動將變量恢復(fù)為原先的值。從效果上來看,這個變量被暫時借用了片刻。local 和 my 的區(qū)別local是全局變量,可以想成“save”(在子例中調(diào)用時),在所有新代碼中只用my,my比local快??勺冮L參數(shù)列表在perl中,經(jīng)常傳遞給子例程任意長度的參數(shù)列表。子例程可以查看@_數(shù)組,從而輕松地判斷參數(shù)的個數(shù)。但在實際的perl編程中,這類檢查幾乎沒有用過,最好是讓子例程適應(yīng)參數(shù)。一個允許任意參數(shù)的例程$maximum = &max(3,5,10,4,6);sub max {my ($max_so_far) = shift @_;foreach (@_) {if ( $_ > $max_so_far) {$max_so_far = $_;}}$max_so_far;}這段代碼使用了被稱作“高水位線(high-water mark)的算法。在一次洪水之后,當(dāng)水最后一次漲潮和退潮時,高水位線顯示了曾經(jīng)達(dá)到的最高水位??盏膮?shù)列表返回一個undef。詞法(my)變量的說明my可以在任何塊中使用,而不僅僅在子例程中。例如可以在if,while or foreach中。use strict pragmaperl是一種特別寬松的語言,但也許你想讓perl把規(guī)則加強一些,這可以用user strict pragma(編譯指示)來安排。pragma中給編譯器的提示,告訴它關(guān)代碼的一些信息,這里,use strictpragma是告訴perl編譯器,它應(yīng)該在本塊或源文件的其余部份強制使用一些好的程序設(shè)計規(guī)則。return操作符該操作符立即從子例程中返回一個值。省略與字符(&)原則在除與內(nèi)置函數(shù)名一致,其它子例程都可以省略與字符。第五章 散列什么是散列?散列(hash)是一個數(shù)據(jù)結(jié)構(gòu),與數(shù)組相同的是它可以含有任意數(shù)目的值并隨意讀取它們。但與數(shù)組中由數(shù)字對值進(jìn)行索引不同,散列用名字(name)查找值。也就是說,索引不再是數(shù)字,而是任意的惟一字符串,稱之為鍵(key)。它是一桶數(shù)據(jù),不存在第一項,它是一團糟的,隨意的,沒有固定的順序。鍵總是被轉(zhuǎn)成字符串,如用數(shù)值50/20做鍵,它就會被變成“2.5”。散列可以任意大小,從空散列直以填滿內(nèi)存。在perl中巨大的散列并不可怕,從三個和三百萬個鍵值對中取出一個數(shù)的速度差不了多少。為什么要用散列你有一組數(shù)據(jù)與另外一組數(shù)據(jù)相關(guān)。如名 姓主機名 ip地址ip地址 主機名單詞 單詞出現(xiàn)的次數(shù)用戶名 用戶使用的硬盤塊數(shù)駕照號碼 名字如果你的任務(wù)描述中包含“找到重復(fù)項”,“唯一的”,“交叉引用”,或“查表”之類的詞語,那么散列就會在實現(xiàn)中很有用處。散列元素訪問使用如下語法:$hash{$some_key}$a{"home"} = "first";$a("hotel"} = "second";當(dāng)你在一個已存在的散列中存入東西時,會覆蓋以前的值。訪問散列之外的元素會得到undef:$a = $b{"test"}; 這里沒有test,得到undef。作為一個整體的散列要訪問整個散列,就使用%號做前綴。為方便起見,可以將散列轉(zhuǎn)換為一個列表,并轉(zhuǎn)換回來,給散列賦值是一個列表上下文,這個表由鍵-值對組成%hash = ("aa",33,"bay",11,2.5,"hello","cc","bb\n");展開散列(unwind),把散列轉(zhuǎn)換回鍵-值對應(yīng)列表。次序亂了,但鍵-值還是成對出現(xiàn)的。@array = %hashprint "@array";bay,11,2.5,hello,cc,bb(一個換行符),aa,33散列賦值%new_hash = %old_hash perl將%old_hash展開成一個鍵-值對列表,并賦值給%new_hash。%inverse_hash = reverse %any_hash 生成逆散列,鍵變值,值變鍵。前提是原散列值要唯一。大箭頭用大箭頭把散列中的鍵-值對組織起來。my %hash = ("aa" => "test1","bb" => "test2","cc" => "test3", 最后額外的逗號是無害的);散列函數(shù)keys函數(shù)得到一個散列中所有當(dāng)前鍵構(gòu)成的一個列表,values函數(shù)得到一個相應(yīng)的值。my %hash = ("a" => "test1,"b" => "test2","c" =>"test3");my @k = keys %hash 得到"a","b","c"。my @v = values %hash 得到"test1","test2","test3"。在一人標(biāo)量上下文中,這些函數(shù)給出散列的元素個數(shù)。my $count = keys %hash 得到3,即有三個鍵-值對。each函數(shù)該函數(shù)可以遍歷一個完整的散列。每次返回一個鍵-值對作為一個二元元素列表。最后返回一個空列表。while ( ($key,$value) = each %hash ) {print "$key => $value\n";}exists函數(shù)查看某鍵是否在散列中。存在就返回真,不存在就返回假。delete函數(shù)從散列中刪除指定的鍵(和相應(yīng)的值)。如無此鍵,它的任務(wù)就結(jié)束。此時沒有警告或出錯信息給出來。第六章 I/O基礎(chǔ)從標(biāo)準(zhǔn)輸入進(jìn)行輸入while (defined($line = <STDIN>)) {print "I saw $line";};因為行輸入操作符在你到達(dá)文件末尾時會返回undef,所以可以用它方便地跳出循環(huán)。從鉆石操作符進(jìn)行輸入“<>”是一種特殊的行輸入操作符,它可以是也可以不是來自鍵盤的輸入。while (defined($line = <>)) {chomp($line);print "It was $line that I saw!\n";};如果用a,b,c三個參數(shù)調(diào)用該程序,將打印三個文件的內(nèi)容。使用鉆石操作符,就好像輸入文件被合并到一個大文件中。上面程序可用快捷方式寫成:while (<>) {chomp;print "It was $_ that I saw!\n";};大多數(shù)linux標(biāo)準(zhǔn)工具中,短橫-代表標(biāo)準(zhǔn)輸入流。通常在一個程序中只用一個鉆石操作符,當(dāng)初學(xué)者在程序中放第二個鉆石時,其實他們一般是想用$_。記住,鉆石操作符讀取輸入,但輸入本身是在$_中。調(diào)用參數(shù)鉆石操作符并不是直接從字面上讀取調(diào)用參數(shù),它實際上讀取@ARGV數(shù)組。它被perl解釋器預(yù)設(shè)為調(diào)用參數(shù)的列表。在程序中可以對該數(shù)組進(jìn)行賦值等操作。@ARGV = qw# a b c #; 強制讀取這三個文件while (<>) {chomp;print "It was $_ that I saw!\n";};向標(biāo)準(zhǔn)輸出進(jìn)行輸出print @array; aabbccprint "@array"; aa bb ccprint <>; cat 的源代碼print sort <>; sort 的源代碼用printf進(jìn)行格式化輸出,和c類似。數(shù)組與printf可動態(tài)形成格式字符串。my @items = qw ( a b c );my $format = "the items are:\n".("%10s\n" x @items); 在標(biāo)量上下文中使用@items得到它的長度printf $format,@items 在列表上下文中使用@items得到它的內(nèi)容上下文太重要了。要好好感受。第七章 正則表達(dá)式的概念正則表達(dá)式(regular expression),在perl中經(jīng)常被稱為模式(pattern),是與一個給定字符串匹配或不匹配的模版。不要把正則表達(dá)式和被稱為glod的shell的文件名匹配模式混淆。比如*.pm匹配以.pm結(jié)尾的文件名。使用簡單的模式要比較一個模式和$_的內(nèi)容,只需把模式放在一對斜杠之間,如下:$_ = "aabbkdkdk";if ( /aabb/ ) {print "it matched!\n";};關(guān)于元字符在正則表達(dá)式中有一組具有特殊意義的字符,叫元字符,如:.號匹配任意單個字符(但不匹配換行符),加反斜杠會使它不再特殊。一對反斜杠配置一個真正的反斜杠。簡單的數(shù)量符在模式中重復(fù)一些東西。*號匹配前面的條目0次或多次。如:/foo\t*test/匹配在foo和test間任意數(shù)目的制表符。.* 匹配任意字符、任意次數(shù)。+ 匹配前面的條目一次或多次。? 匹配前面的條目是可選的,只能發(fā)生一次或0次(即沒有)。模式中的分組可以用()括號分組,所以小括號也是元字符。如:/abc+/ 匹配abccccccccccccccccc/(abc)+/ 匹配abcabcabcabcabc/(abc)*/ 匹配任意字符串,甚至是空串。選擇豎線 | 表示要么是左側(cè)匹配,要么是右側(cè)匹配。此時讀做“或”。/aa|bb|cc|/ 匹配一個含有aa或bb或cc的字符串。/aa( |\t)+bb/ 匹配aa和bb中間被空格、制表符或兩者的混合串分隔/aa( +|\t+)bb/ 匹配aa和bb中間必須全是空格,或全是制表符/aa(and|or)bb/ 匹配aa and bb 和aa or bb一個模式測試程序下面這個程序有助于在一些字符串上測試一個模式,看看它匹配了什么,在哪里匹配的。#!/usr/bin/perlwhile (<>) {chomp;if (/your_pattern_goes_here/) {print "Matched : |$`<$&>$‘|\n";} else {print "No match.\n";}};第八章 正則表達(dá)式提高字符類字符類(character class)即在一對中括號中列出的所有字符,可以匹配類中的任何單個字符。例如:[abcdefg]可以匹配這七個字符中的任何一個??捎谩?”指定一個范圍。如[a-h],[1-9]等。[\001-\177]匹配任何7比特ASCII碼。中括號中的“^”號是取反的意思,如[^abc]匹配除abc外的任何單個字符。字符類快捷方式有些字符類的使用特別頻繁,所以就有了快捷方式。如:所有數(shù)字的字符類[0-9]可以縮寫成\d,[A-Za-z0-9_]縮寫成\w。\s匹配空白,它和[\f\t\n\r ]等同,即等同一個含五種空白字符的字符類,它們是換頁符,制表符,換行符,回車符和空格字符自已。\s只匹配類中的一個字符,所以一般用\s*匹配任意數(shù)量的空白(包括沒有空白),或用\s+匹配一個或多個空白字符。以上快捷方式的反置寫法是用大寫形式表示,\D,\W,\S。/[\dA-Fa-f]/匹配十六進(jìn)制數(shù)字。/[\d\D]/匹配任何數(shù)字或任何非數(shù)字,也就是任何字符,包括換行符。“.”匹配除換行符外的所有字符。/[^\d\D]/表示什么都不匹配。通用數(shù)量符前面我們見過三個數(shù)量符*,+,?。但如果這三個不能滿足你的需要,也可以用大括號{}中的一對由逗號隔開的數(shù)字來指定重復(fù)的最少和最多次數(shù)。如/a{5,15}/匹配重復(fù)5次到15次的字母a。如果省略第二個數(shù)(但包含逗號),那么匹配的次數(shù)就沒有上限。如/a{3,}/就匹配一行中連續(xù)出現(xiàn)的3個或多個a,它沒有上限。如果連逗號也沒有了,那么給出的數(shù)字就是一個準(zhǔn)確的數(shù)字。如/a{3}/匹配3個a。* 等價 {0,}+ 等價 {1,}? 等價 {0,1}錨位符錨位符(anchor)可以用來為模式指定字符串的特定位置?!癪”標(biāo)志字符串的開頭,“$”標(biāo)志字符串的結(jié)尾。如/^a/匹配處于字符頭的abc,不能匹配dda,/b$/匹配處于字符尾的aab,不能匹配abc。/^s*$/匹配一個空行/^abc$/匹配abc,又匹配abc\n單詞錨位符\b可以匹配一個單詞的兩端,可以用/\babc\b/來匹配單詞abc。可以用一個單詞錨位符,如,/\bth/可以匹配this,these,但不匹配method。/er\b/匹配hander,woner,但不匹配gerenic,lery.非單詞邊界錨位符是\B,它匹配任何\b不匹配的地方。如/\bsearch\B/會匹配searches,searchingand searched.但不能匹配search or researching。記憶的小括號()可以用來把模式的一些部份組合起來,它還有第二個功能,它們要求正則表達(dá)式引擎記住與小括號中的模式匹配的那部份子串。反向引用反向引用(backreference)就是回頭引用在當(dāng)前模式處理過程中保存的記憶。用一個么斜杠來構(gòu)成,如\1包含第一個正則表達(dá)式記憶。即被第一對小括號匹配的字符串部份。反向引用被用來匹配與模式在前面匹配的字符串完全一樣的字符串。所以/(.)\1/匹配任意單個字符,在記憶1中記住它,然后再與記憶1匹配。換句話說,它匹配任意字符,后跟同一個字符。這樣,這個模式會匹配雙字母式的字符串。如bamm-bamm和betty。它和/../不一樣,/../匹配任意字符,后跟任意字符,它們兩個可以一樣,也可以不一樣。記憶變量正則表達(dá)式記憶的內(nèi)容在模式匹配結(jié)束后仍可通過特殊變量$1得到。優(yōu)先級分四個級別1、最上面的是小括號。2、是數(shù)量符,*,+,?,{1,2},{1,},{1}3、是錨位符和序列,^,$,\b,\B。4、是堅線 | 。優(yōu)先級例子/^aaa|bbb$/可能不程序員的意思,它只匹配字符串a(chǎn)aa的開頭或字符串bbb的未尾。程序員更可能想要的是/^(aaa|bbb)$/,它匹配一行中沒有其它東西,除了aaa或bbb以外。第九章 使用正則表達(dá)式使用m//進(jìn)行匹配一對斜杠實際上是m//(模式匹配)操作符的一個快捷方式。如我們在qw//中所中,你可以選擇任何定界符對把內(nèi)容括住。如m<aaa>,m(aaa),m{aaa},m[aaa],m!aaa!等。如果選擇了反斜杠,就可以省略m。選項修飾符用/i進(jìn)行不區(qū)分大小寫的匹配。用/s進(jìn)行任何字符的匹配,包括換行符。它把模式中的每個點變成和字符類[\d\D]一樣,匹配任何字符,包括換行符??山M合使用修飾符/is,順序并不重要。綁定操作符=~my $some_other = "I dream of betty rubble";if ($some_other =~ /\brub/) {print "Aye,there‘s the rub.\n";}看起來像個賦值語句,但它不是的。它是說“這個模式缺省時匹配$_中的東西---但現(xiàn)在讓它匹配左側(cè)的字符串”。如果沒有綁定操作符,表達(dá)式就缺省使用$_。匹配變量可以用$1,$2,$3,$4引用正則表達(dá)式記憶的第一到第四個記憶。匹配變量是正則表達(dá)式強大功能的一個重要部份,它能讓我們?nèi)〕鲆粋€字符串的一部份。$_ = "hello there,neighbor";if (/\s(w+),/) { 記住空格和逗號之間的單詞print "the word was $1\n."; $1 就是 there}匹配變量可以是空串。記憶的持久性匹配變量一般保留到下一次模式匹配成功。也就是除非匹配成功,否則你不應(yīng)該使用這些匹配變量。自動匹配變量$& 實際與模式匹配的那部份字符串就保存在這里。if ("hello there, neighbor" =~ /\s(w+),/) {print "that actually matched ‘$&‘.\n";}整個匹配部份是" there,"(一個空格,there,一個逗號),$1中是there,而$&中是整個匹配部份。匹配部份之前的東西被存在$`,之后的東西被存在$‘。也就是說,$`含有正則表達(dá)式引擎在找到匹配之前需跳過的部份,而$‘則含有模式?jīng)]有到達(dá)的字符串的剩余部份。如果把這三個字符串按順序連在一起,那么你總會得到原字符串。第七章的模式測試程序就是使用了這三個神秘代碼。print "match:|$`<$&>$‘|\n"使用自動匹配變量的代價是,會使用其它正則表達(dá)式的運行會變得慢一些。所以很多perl程序員都盡量避免使用這些自動匹配變量。相反,他們會采用一些方法,例如,如果你只需要$&,那就在整個模式的周圍加一對括號,然后使用$1。用s///進(jìn)行查換并替換$_ = "he‘s out bowling with barney tonight.";s/barney/killer; 用killer替換barney,如果匹配失敗,什么也不會發(fā)生。print "$_\n";s///有一個返回值,替換成功,則為真,否則為假。用/g進(jìn)行全局替換s///只替換一處,/g修飾符告訴s///進(jìn)行所有可能的無交迭替換。全局替換的一個相當(dāng)常見的使用是壓縮空白,把任意數(shù)量的空白變成一個空格。s/\s+/ /g; 壓縮空白s/^\s+//; 把前面的空白刪除s/\s+$//; 把結(jié)尾的空白刪除s///也可用不同的定界符,如#,!號等,但如果使用成對的字符,因為它有左右之分,所以必須用兩對,一結(jié)放模式,一對放替換串,如s[aaa][bbb],s(aaa)(bbb),甚至也可以用s<aaa>(bbb)這樣不成對的定界符。s///也和m//一樣,有/i,/s修飾符和=~綁定操作符。$file_name =~ s/^.*///s; 在$file_name中,去掉所有unix風(fēng)格的路徑。大小寫轉(zhuǎn)換\U 強制后面的字符都用大寫 s/(aaa|bbb)/\U$1/gi AAA BBB\L 強制后面的字符都用小寫 s/(aaa|BBB)/\L$1/gi aaa bbb用\E關(guān)閉,當(dāng)寫成小寫形式時,\u,\l就只影響下一個字符。\u\L或\L\u 代表首字符大寫,與順序無關(guān)。split操作符它把一個字符串按照分割子(separator)分開。@fields = split /:/,"abc:def::a:b"; 得到("abc","def","","a","b")。@fields = split /:/,":::a:b:c:::"; 得到("","","","a","b","c"),結(jié)尾空字段被丟棄。在空白處分割也是常見的,使用/\s+/模式。split的缺省行為是在空白處分割$_。如my @fields = split; 等同于split /\s+/, $_;join函數(shù)在某種意義上,join完成split的相反過程。它把一組片斷粘合起來形成一個字符串。my $a = join ":",1,2,3,4,5; 則$a 是"1:2:3:4:5"join可以和split配合使用,把一個字符串分割后用不同的定界符恢復(fù)它。如可以把1,2,3 變成 1-2-3.第十章 更多的控制結(jié)構(gòu)unless控制結(jié)構(gòu)if是表達(dá)式為真時執(zhí)行,如果希望表達(dá)式為假時執(zhí)行可用unless(除非)。表示除非表達(dá)式為真,否則運行這個代碼。它就像一個具有相反條件的if語句,也可以理解成一個獨立的else子句。unless ($aa = ~/^[A-Z_]\w*$/i) {print "the value of \$aa doesn‘t look like a perl identifier name.\n";}等同于if ($aa =~ /^[A-Z_]\w*$/i) {} else {print "the value of \$aa doesn‘t look like a perl identifier name.\n";}等同于if (!$aa =~ /^[A-Z_]\w*$/i) {print "the value of \$aa doesn‘t look like a perl identifier name.\n";}以上語句都被編譯成相同的內(nèi)部字節(jié)碼,但unless最自然。unless的else子句unless ($aa =~/^(bb)/) {print "this value like bb.\n";} else {print "do you see what‘s going on here?\n";}等同于if ($aa =~/^(bb)/) {print "do you see what‘s going on here?\n";} else {print "this value like bb.\n";}until控制結(jié)構(gòu)while的反置結(jié)構(gòu)。until ($a > $b) {$a *= 2;}這個循環(huán)一直執(zhí)行,直到條件表達(dá)式返回真為止。表達(dá)式修飾符print "$n is a negative number.\n" if $n < 0;等同于if ($n < 0) {print "$n is a negative number.\n";}前一種寫法更緊湊。讀起來很像自然英語。還有:print " ",($n +=2) while $n < 10;$i *= 2 until $i >$j;&greet($_) foreach @person;裸塊控制塊所謂的“裸(naked)塊”,指的是沒有關(guān)鍵字或條件的塊。如:while (condition) {body;body;body;}現(xiàn)在把while關(guān)鍵字和條件去掉,就得到一個裸塊。{body;body;body;}它只執(zhí)行一次,然后就結(jié)束,其中一個作用是提供一個臨時詞法變量的作用域。一條通用的原則,所有變量就應(yīng)該在最小的作用域中聲明。如果你需要一個只用在幾行代碼中的變量,那么你可以把這些行放在裸塊中,并在該塊中聲明這個變量。elsif子句如果你需要檢查一組條件,一個接一個,看看哪個條件為真,就可以用elsif子句(注意不是elseif)。perl會逐個測試條件表達(dá)式,當(dāng)一個條件成功就執(zhí)行相應(yīng)的代碼。但如果測試項太多,就不要使用這種方式,應(yīng)該用類“case or switch”的語句。自遞增和自遞減++ $a++; $a值不變。++$a; 把$a增1,存到$a里。-- $a--; $a值不變。--$a; 把$a減1,存在$a里。for控制結(jié)構(gòu)for ($i =1 ;$i <=10;$i++) {print "I can count to $i!.\n";}for ($_ = "aaabbbccc";s/(.)//; ) { 當(dāng)s///成功時執(zhí)行循環(huán)。print " one character is :$1\n."}每次迭代時都會去掉一個字母。當(dāng)字符串為空時,替換失敗,循環(huán)結(jié)束。以下用for實現(xiàn)的無限循環(huán)for (;;) {print "this is an infinite loop.\n";}以下為用while實現(xiàn)的無限循環(huán),一種更具perl特色的寫法。while (1) {print "this is an infinite loop.\n";}foreach和for之間的秘密聯(lián)系在perl內(nèi)部,foreach 和 for 完全等價。for (1..100) { 實現(xiàn)是一個從1到100的foreach循環(huán)print "I can count to $_.\n";}在perl中,foreach總是被寫成for,因為可節(jié)省4個字符的輸入,因為懶惰是perl程序中的經(jīng)典品質(zhì)。循環(huán)控制last操作符 立即終止一個循環(huán)的執(zhí)行(與c中的break相似)。作用于當(dāng)前運行的最內(nèi)層循環(huán)塊。next操作符 控制從循環(huán)的下一個迭代繼續(xù)(與c中的continue相似)redo操作符 回到當(dāng)前循環(huán)的開頭,但不測試條件表達(dá)式,進(jìn)入下一次迭代。next 和 redo 最大的區(qū)別在于next會進(jìn)入到下一次迭代,而redo則重新執(zhí)行當(dāng)前的迭代。帶標(biāo)簽的塊很少使用,也就是命令一個循環(huán),以便從內(nèi)層循環(huán)中直接跳出。LINK: while (<>) {foreach (split) {last LINK if /__END__/; 跳出LINE循環(huán)。...;}}邏輯操作符&& 相當(dāng)于and|| 相當(dāng)于or它們被稱為短路操作符。三元操作符 ?和c的一樣,它就像一個if-then-else測試。expression ? if_true_expr : if_false_expr一個利用三元操作符寫的多路分支程序my $size =($width < 10) ? "small" :($width < 20) ? "medium" :($width < 50) ? "large" :"extra-large"; 缺省值。使用部份計算操作符的控制結(jié)構(gòu)&&,||,?:都有一個共有的屬性,依賴于左側(cè)值的真假,它們可能計算可不計算一個表達(dá)式,因此叫部份計算(partial-evaluation)操作符。因此它天生就是一種控制結(jié)構(gòu)。第十章 文件句柄和文件測試什么是文件句柄?文件句柄(filehandle)是Perl程序中的一個名字,表示你的Perl進(jìn)程與外面世界的i/o連接。它是一個連接的名字,并不是一個文件的名字。文件句柄的命名方式與其它perl標(biāo)識符一樣,建議用大寫字母。Perl為了自已使用,已經(jīng)有六個特殊的文件句柄名:STDIN,STDOUT,STDERR,DATA,ARGVAND ARGVOUT。打開一個文件句柄open CONFIG,"test"; 打開test文件,它所包括的東西通過名為CONFIG的文件句柄為我們的程序所使用。open CONFIG,"<test"; 打開test文件,顯式說明這個文件名用于輸入。open CONFIG,">test"; 打開test文件,顯式說明這個文件名用于輸出。為了輸出打開文件句柄CONFIG到新文件test。open CONFIG,">>logtest"; 打開logtest文件,用于附加。如果文件不存在則生成它。關(guān)閉一個文件句柄close CONFIG;退出程序時文件句柄會自動關(guān)閉,但建議最好在完成一個文件句柄的使用后不久就關(guān)閉它。壞文件句柄系統(tǒng)中會存在壞文件句柄,如果你試圖向一個壞文件句柄寫入,那么數(shù)據(jù)會被無聲地丟棄。在編寫腳本時用perl -w會打開警告顯示。用die表明致命錯誤unless (open LOG,">>logtest") {die "Cannot create logtest:$!";}或者用另外一種更好的寫法open LOG, ">>logtest" or die "Cannot create logtest:$!"; 使用or操作符。如果open成功,返回真,or結(jié)束,如果open失敗,返回假,or會繼進(jìn)行到右側(cè)代碼。伴隨一條消息死去。你可以用語言去讀它,“打開這個文件,或死去”。$!是系統(tǒng)給出的出錯提示信息,如果die表明的錯誤并非來自一個系統(tǒng)請示失敗,請不要包含$!。die "Not enouht arguments.\n" if @ARGV < 2; 命令參數(shù)不夠兩個時,程序退出。使用warn發(fā)出警告信息與die類似,但它不退出程序。使用文件句柄一旦打開一個文件句柄,你就可以讀入行。像使用STDIN從標(biāo)準(zhǔn)輸入讀取一樣。例如從unix的passwd文件中讀取行:open PASSWD, "/etc/passwd"or die ”How did yo get loged in?($!)";一個為寫入或附加打開的文件句柄可以和print or printf一起使用,緊跟在其后但在參數(shù)列表之前:print LOG "filehandle test.\n" 輸出到LOG改變?nèi)笔〉妮敵鑫募浔笔∏闆r下,如果沒有給print指定一個文件句柄,輸出就會發(fā)送到STDOUT,但這個行為可以用select操作符改變。select LOG;print "this message send to LOG.\n";一旦選擇一個文件句柄作為缺省的輸出,它會一直保留,這樣會把后面的程序搞糊涂,所以要在完成后及時設(shè)回STDOUT。select STDOUT;重新打開一個標(biāo)準(zhǔn)文件句柄如果三個系統(tǒng)句柄(STDIN,STDOUT,STDERR)的任何一個不能打開,Perl會友好地恢復(fù)原來的那個,也就是說perl只有在看到新的連接打開成功時幫把原來的關(guān)掉。文件測試在perl中有一組完整的測試,你可以用來了解文件的信息。-e 測試文件是否存在die "ooo!my gods,a file called "$file"already exists.\n" if -e $file;-M 檢查一個文件是否最新warn "config file is looking pretty old!\n"if -M CONFIG > 28;文件測試和它們的含義-r 文件或目錄對該(有效)用戶或組可讀-w 文件或目錄對該(有效)用戶或組可寫-x 文件或目錄對該(有效)用戶或組可執(zhí)行-o 文件或目錄被該(有效)用戶或組所有-R 文件或目錄對該實際用戶或組可讀-W 文件或目錄對該實際用戶或組可寫-X 文件或目錄對該實際用戶或組可執(zhí)行-O 文件或目錄被該實際用戶或組所有-e 文件或目錄名存在-z 文件存在,大小為零,對目錄總為假-s 文件或目錄存在,大小非零,單位為字節(jié)-f 條目是個普通文件-d 條目的個目錄-l 條目是個符號鏈接-S 條目是個套接字-p 條目是個命名管道(一個fifo)-b 條目是個塊特殊(block-special)文件(如一個可裝載磁盤)-c 條目是個字符特殊(character-special)文件(如一個i/o設(shè)備)-u 文件或目錄是setuid-g 文件或目錄是setgid-k 文件或目錄的粘著位sticky bit被設(shè)置-t 文件句柄是個TTY(可以由isatty()函數(shù)返回,文件名不能由本測試來測試)-T 文件像個“文本”文件-B 文件像個“二進(jìn)制”文件-M 更改年齡(單位為天)-A 訪問年齡(單位為天)-C Inode更改年齡(單位為天)stat和lstat函數(shù)stat返回unix的stat系統(tǒng)調(diào)用返回的所有信息。它的操作數(shù)是一個文件句柄或是一個文件名。返回值可能是一個空列表,表示stat失敗(通常是文件不存在),或者是一個13個元素的數(shù)字列表??捎靡韵聵?biāo)量變量列表描述出來。my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) =stat($filename);$dev 文件設(shè)置號$ino 文件inode號$mode 文件權(quán)限位和一些特別位$nlink 指向文件或目錄的鏈接數(shù)$uid 文件的用戶id$gid 文件的組id$size 文件大小(以字節(jié)為單位)$atime $mtime $ctime 訪問,修改,改變時間$blksize 塊大小$blocks 塊數(shù)對符號鏈接使用stat將返回該鏈接所指的東西的信息,而不是符號鏈接本身,除非這個鏈接碰巧沒有指向任何目前可以訪問的東西。如果你需要(基本上沒用)符號鏈接本身的信息,就使用lstat。如果操作數(shù)不是一個符號鏈接,lstat則返回與stat一樣的東西。localtime函數(shù)把電腦時間轉(zhuǎn)換成人可以看得明白的日期時間。my $timestamp = 19809999393my $date = localtime $timestamp在列表上下文中,localtime返回一個數(shù)字列表。my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime $timestamp$mon 表示月份,從0-11。$year 表示自1900年起的年數(shù),要加上1900才是真正的年數(shù)。按位操作符& 按位與----得到哪些位在兩個操作數(shù)中同時為真| 按位或----得到哪些位在兩個操作數(shù)中至少有一個為真^ 按位異或----得到哪些位在兩個操作數(shù)中只有一上為真<< 按位左移----把左操作數(shù)的位移動由右操作數(shù)給定的次數(shù),在低位補上0>> 按位右移----把左操作數(shù)的位移動由右操作數(shù)給定的次數(shù),低位會被丟棄~ 按位取反,也被稱為一元位補----返回與操作數(shù)的每位相反的數(shù)使用位串如果一個按位操作符的任何操作數(shù)是一個字符串,perl就會進(jìn)行位串操作。也就是說"\xAA"| "\x55" 會得到字符串"\xFF"。使用特殊的下劃線文件句柄_ 特殊的文件句柄,使perl用上次文件測試、stat,lstat函數(shù)操作后留在內(nèi)存中的信息。第十二章 目錄操作改變目錄樹chdir操作符可以改變工作目錄,就像cd命令一樣。chdir "/etc" or dir "cannot cddir to /etc:$!";globshell通常會把每個命令中的文件名模式擴展為匹配的文件名,這就稱為glod。 如ls *.txtperl中的類似的glob操作符。my @all_files = glob "*"; 得到當(dāng)前目錄中的所有文件,不包含以句點開頭的文件。my @pm_files = glob ".pm"; 得到以.pm結(jié)尾的文件。glob的另一種作法在一些老程序中用<>代替glob操作符my @all_files = <*>;目錄句柄目錄句柄(directory handle)和文件句柄在外表和操作上都很像,可以打開它(用opendir),讀取它(用readdir),關(guān)閉它(用closedir)。它讀出的是目錄的內(nèi)容。my $dir_to_process = "/etc";opendir DH,$dir_to_process or die "cannot open $dir:$!";foreach $file (readdir DH) {print "one file in $dir is $file\n";}closedir DH;與文件句柄類似,目錄句柄會在程序結(jié)束時或該目錄句柄在其它目錄上重新打開時被自動關(guān)閉。如果我們只想要那些以pm結(jié)尾的文件,可以在循環(huán)中使用一個跳過函數(shù)while ($name =readdir DIR) {next unless $name =~ /\.pm$/;.....}如果要非點文件可以用:next if $name =~ /^\./;如果想要除. 和 ..之外的文件可用: next if $name eq "." or $name eq "..";readdir操作符返回的文件沒有路徑名部份,僅僅是目錄內(nèi)的文件名。如passwd,而不是/etc/passwd名字補丁,加上路徑名。opendir SOMEDIR, $dirname or die "cannot open $dirname:$!";while (my $name = readdir SOMEDIR) {next if $name =~ /^\./; 跳過點文件$name = "$dirname/$name"; 補上路徑名next unless -f $name and -r $name 只要可讀文件.....}遞歸的目錄列表遞歸地訪問目錄可用File::Find庫。以進(jìn)行簡潔的遞歸目錄處理。不用自已寫代碼。第十三章 處理文件和目錄刪除文件在perl中用unlink操作符刪除文件,同shell的rm命令一樣。unlink "aa","bb","cc"; 把這三個文件刪除。與glob函數(shù)結(jié)合起來可以一次刪除多個文件unlink glob "*.o"; 刪除當(dāng)前目錄下以.o結(jié)尾的文件,與rm *.o相似。unlink的返回值告訴我們有多少文件被成功刪除。my $successful = unlink "aa","bb","cc";print "I delete $successful file(s) just now.\n";如果想知道那個文件被刪除,可用循環(huán),一次刪除一個文件。foreach my $file (qw/aa,bb,cc/) {unlink $file or warn "failed on $file:$!";}一個很少人知道的有關(guān)unix的事實。如果你有一個文件,你對它不能讀,不能寫,不能執(zhí)行,甚至文件可能并不屬于你,但你仍然可以刪除它。這是因為unlink一個文件的權(quán)限不依賴于文件本身的權(quán)限位,起作用的其實是包含這個文件的目錄的權(quán)限位。只要目錄是可寫的,就可以刪除該目錄中不屬于自已的文件。在unix中可以通過設(shè)置sticky bit解這個問題,以保護(hù)可寫目錄。重命名文件rename "old","new";類似于mv命令。rename失敗時返回假,并在$!中設(shè)置操作系統(tǒng)的錯誤信息。因此可用or die或or warn顯示給用戶。一個把所有以.old結(jié)尾的東西rename為以.new結(jié)尾的perl程序。foreach my $file (glob "*.old") {my $newfile = $file;$newfile =~ s/\.old$/.new/; 由于.new不是模式,所以點號不用加反斜杠。if (-e $newfile) {warn "can‘t rename $file to $newfile:$newfile exists.\n";} elsif ( rename $file, $newfile) {} else {warn "rename $file to $newfile failed:$!\n";}}鏈接和文件每個文件都被存在一個編了號的inode中,每個inode都包含一個稱為鏈接計數(shù)(link count)的數(shù)字,當(dāng)inode沒有列在任何目錄中時,鏈接計數(shù)總是0,也就是空,可以分配給文件。當(dāng)inode被加到一個目錄中時,鏈接計數(shù)會遞增;如果此列表項被刪除,鏈接計數(shù)會遞減。目錄包含.,也就是指向自已的inode,所以目錄的鏈接計數(shù)應(yīng)該總是至少為2。文件也可以不止一個列表項,如鏈接文件。在perl中用link "aa","bb"建立一個指向aa的鏈接bb。類似于在unix shell一執(zhí)行"ln aa bb"?,F(xiàn)在aa,bb都有相同的inode值,兩個文件有相同的大小,相同的內(nèi)容。在aa中加入一行,也會在bb中加入一行。如果意外刪除了aa,數(shù)據(jù)并不會丟失,可以在bb中找回來。反之也一樣。但如果兩個文件都刪除了,則數(shù)據(jù)就會丟失。目錄列表項中的鏈接規(guī)則1、 一個給定的目錄列表項中的inode號都指向同一個安裝卷上的inode。這條規(guī)則保證,如2、 果物理媒介被移到了另一臺機器上,所有的目錄仍和它們的文件呆在一起。這就是為什3、 么可用rename把文件從一個目錄移到另一個目錄的原因,但兩個目錄必須在同一個文4、 件系統(tǒng)(安裝卷)中。鏈接不能用于目錄。2、不能給目錄起新的名字。因此目錄不能用于鏈接。以上討論的是硬鏈接,還有一個符號鏈接,也叫軟鏈接,能繞過這硬連接的限制。symlink "aa","bb";or warn "cannot symlink aa to bb:$!";這和unix shell 中的"ln -s aa bb" 類似。要想知道符號鏈接指向哪里,可以使用readlin函數(shù)。如果不是符號鏈接,則返回undef。兩種鏈接都要以用unlink刪除。建立和刪除目錄mkdir函數(shù)可以在一個已有的目錄中建立一個目錄。返回真時表示成功。mkdir "aaa",0755 or warn "cannot make aaa directory:$!";第二個參數(shù)是新生成目錄的權(quán)限位。以0開頭,這個是一個八進(jìn)制值。oct函數(shù)強制對一個字符串按八進(jìn)制解釋,不論前面有沒有0:刪除空目錄,可用rmdir函數(shù)。rmdir glob "aa/*"; 刪除aa/下所有空目錄。rmdir操作符對非空目錄操作會失敗。所以要先用unlink刪除文件,再刪除目錄。修改權(quán)限perl中有一個chmod函數(shù),和unix shell中的chmod完成類似功能。chmod 0755, "aa","bb";perl中不接受符號權(quán)限表達(dá)式方式,如+x,go=u-w等。改變所有者chown函數(shù)可以改變一組文件的所有者和屬組。chown 1004,100,glob "*.o";可用getpwnam把用戶名翻譯成一個數(shù)字,用getgrnam函數(shù)把組名翻譯成一個數(shù)字。改變時間戳utime函數(shù)可修改文件的訪問時間和修改時間。my $now = time;my $ago = $now -24*60*60; 每天的秒數(shù)utime $now,$ago,glob "*"; 把訪問時間設(shè)為現(xiàn)在,修改時間設(shè)為一天以前第三個時間ctime的值在對文件做任何改變時,總被設(shè)為“現(xiàn)在”,因此沒辦法用utime函數(shù)來設(shè)置它。因為在你設(shè)置完后它會立即被重置為“現(xiàn)在”,這是因為它的主要目的就是進(jìn)行增量備份:如果文件的ctime比備份磁帶上的日期要新,就說明又需要備份了。使用簡單的模塊File::Basename模塊 從文件名中抽取基名,取不包括路徑的文件名。通過use命令聲明一個模塊use File::Basename;這樣,我們就有了一個basename函數(shù)。my $name = "/usr/local/bin/perl";my $basename = basename $name; 得到perl該函數(shù)可用于多平臺,如windows。該模塊中還有一個dirname函數(shù),它把目錄名從一個完整文件名中分離出來。有選擇地使用模塊中的函數(shù)當(dāng)你不需要模塊中的所有函數(shù),或模塊中的函數(shù)和你程序中子例程有沖突時,你可以在聲明模塊時給模塊一個引入列表,只包括需要的函數(shù)。use File::Basename qw /basename/; 只要basename函數(shù),不要其它函數(shù)。use File::Basename qw //; 不要任何函數(shù)。怎么會想要一個空列表呢?這是因為,有引入只是使得我們能使用短的簡單的函數(shù)名,basename,dirname。即使不引入這些名字,我們?nèi)钥梢允褂?,只是在沒有引入時,我們要用全名來調(diào)用它,如:File::Basename::dirname。每個模塊都有缺省的引入列表,查相關(guān)文檔有介紹。File::Spec模塊用來處理文件規(guī)范(file specification)。它是一個OO的模塊。用小箭頭而不是::來引用函數(shù)。$newname = File::Spec->catfile($dirname,$basename);第十四章 進(jìn)程管理通過perl直接啟動其它程序。system函數(shù)system "date"; 啟動unix系統(tǒng)的date命令。子進(jìn)程會運行date命令,它將繼承perl的標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯誤。system ‘ls -l $HOME‘; 注意是用單引號,因為$HOME是shell變量,否則,shell就看不到美元符號。表明要替換的符號。system "long_time_command&"; 把長時間運行的程序放在后臺。system ‘for i in *; do echo ==$1 ==; cat $i; done‘; 可以寫腳本避免shell調(diào)用system操作符時帶多個參數(shù),此時shell就不會卷入。如:system "tar","cvf",$aaa,@bbb; 第一個命令是tar,其余的參數(shù)會一個一個傳遞給它。system的退出狀態(tài)基于子進(jìn)程的退出狀態(tài)。在unix中0表示正常,非0表示出錯。unless (system "date") { 返回0表示成功print "we gave you a date,ok!\n";}exec函數(shù)與system差不多,system會生成一個子進(jìn)程,exec是讓perl進(jìn)程本身去處理所要求的動作。一般用system就可以了。環(huán)境變量當(dāng)你啟動一個新進(jìn)程時,環(huán)境變量就被繼承下來了。在perl中,通過特殊的%ENV散列得到環(huán)境變量,散列中每個鍵表示一個環(huán)境變量。在你的程序剛開始執(zhí)行時,%ENV就從父進(jìn)程(通常是shell)繼承而來。修改這個散列就改變了環(huán)境變量,它又會被新進(jìn)程繼承。$ENV {‘PATH‘} = "/home/mydir/bin:$ENV{‘PATH‘}"; 設(shè)置新的環(huán)境變量,增加了一個路徑delete $ENV{"IFS"}; 刪除“IFS”這個路徑my $make_result = system "make"; 在新環(huán)境變量中執(zhí)行程序使用反引號捕獲輸出當(dāng)使用system and exec時,所啟動命令的輸出都被送到perl的標(biāo)準(zhǔn)輸出上。有時我們需捕獲這些輸出。my $now = `date`;print "the time is now $now."; 已經(jīng)有換行符,不用加\n。與shell差不多。但它把行尾去掉,而perl的輸出包含\n。所以要得到同樣的效果,需加上chomp操作。在列表上下文中使用反引號my $who_text = `who`; 標(biāo)量上下文,得到一個長字符串。my @who_lines = `who`; 列表上下文,得到一個按行分開的數(shù)據(jù)。文件句柄形式進(jìn)程perl可以啟動一個處理活動狀態(tài)的子進(jìn)程。啟動一個并發(fā)子進(jìn)程的語法是把命令當(dāng)做“文件名”用在open調(diào)用中,在命令之前或之后加一個豎線,這是一個“管道”字符,因些,這通常被稱為管道打開(piped open)。open DATE, "date|" or die "cannot pipe from date:$!";豎線在右邊,其標(biāo)準(zhǔn)輸出與文件句柄DATE連接,就像shell中的date | your_program。open MAIL, "|mail merlyn" or die "cannot pipe to mail:$!";豎線在左邊,命令的標(biāo)準(zhǔn)輸入文件句柄MAIL連接,就像shell中的your_program | mail。命令啟動后是個獨立于perl的進(jìn)程。要讀取一個為讀而打開的文件句柄,我們只需進(jìn)行普通的讀:my $now = <DATE>;要想給郵件進(jìn)程發(fā)送數(shù)據(jù),一人簡單的“帶文件句柄的打印”就可以了:print MAIL "the time is now $now.";用fork進(jìn)行深入和復(fù)雜的工作用低級系統(tǒng)調(diào)用實現(xiàn) system "date";命令。defined (my $pid = fork ) or die "cannot fork:$!";unless ($pid) {exec "date";die "cannot exec date:$!";}waitpid($pdi.0);發(fā)送和接收信號向4201發(fā)送一個SIGINT。kill 2, 4201 or die "cannot signal 4201 with SIGINT:$!";你也可用“INT”替代這里的2,因為2號信號就是SIGINT。信號0表示,看看我能不能發(fā)一個個信號,但我并不想現(xiàn)在發(fā)送。因此可用以進(jìn)程探測。unless (kill 0,$pid) {warn "$pid has gone away!";}第十五章 字符串與排序用index尋找子字符串在大字符串中出現(xiàn)的位置。$where = index($big,$small);例子my $where = index ("howdy world","wor") where 是 6 .index還有第三個參數(shù),告訴index從后面某個指定的位置開始搜索,而不是從開頭。可用rindex函數(shù)找到子字符串最后出現(xiàn)的位置。my $last_slash = rindex ("/etc/passwd","/"); 值是4rindex也有可選的第三個參數(shù),但此時給出的是允許的最大返回值。用substr處理一個子字符串substr操作符只作用于一個大字符串的一部分,它看起來如下:$part = substr($string,$initial_position,$length);它取三個參數(shù):字符串值、以零為基準(zhǔn)的初始位置(與index的返回值類似)和子字符串的長度。返回值是一個子字符串:my $mineral = substr ("hello world",6,5); 得到worldmy $rock = substr "hello world,6,10000"; 得到world,第三個參數(shù)可超過實現(xiàn)的字符串長度。如果想確保到達(dá)字符串末尾,不論它多長或多短,則只須省略第三個參數(shù)。始初位置可以是負(fù)值,意思是從字符串的末尾數(shù)起,即-1代表最后一個字符。index and substr可很好地配合工作。如我們可以取出從字線l位置開始的一個子串:my $long = "a very very long string";my $right = substr($long,index($long,"l"));還可以使用綁定操作符(=~)以限制某個操作符只作用于字符串的一部份。substr($string,-20) =~ s/aa/bb/g;但在實現(xiàn)代碼中不會需要這樣的功能。用substr and index能完成的工作多數(shù)也可以用正則表達(dá)式完成。不過substr and index一般會快一些。四個參數(shù)版本的substr,第四個參數(shù)就是做替換的子字符串。my $previous_value = substr($string,0,5,"Goodbye");用sprintf格式化數(shù)據(jù)sprintf 和 printf取一樣的參數(shù)(除了可選的文件句柄之外),但它返回請求的字符串而不是打印它。my $date_tag = sprintf "%4d/%02d/%02d %2d:%02d",$yr,$mo,$da,$h,$m,$s;在本例中,$date_tag得到的東西類似于"2004/01/01 3:00:00"。使用sprintf處理“錢數(shù)”顯示2.50而不是2.5,可用“%.2f”格式完成。my $money = sprintf "%.2f",2.499999";如果你的“錢數(shù)”的太大以至于需要逗號來顯示它的大小,那么可以用以下例程實現(xiàn)。sub money {my $number = sprintf "%.2f",shift @_; 每次通過空循環(huán)時加一個逗號1 while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/; 在合適的地方加上美元符號$number =~ s/^(-?)/$1\$/;$number;第一行格式化第一個參數(shù)以獲得在小數(shù)點后準(zhǔn)確的兩個數(shù)字。如果參數(shù)是數(shù)字12345678.9那么我們的$number就是字符串"12345678.90"。下一行使用一個while修飾符,表示只要替換返回真值(表示成功),循環(huán)體就被執(zhí)行,但循環(huán)體什么都不做。它可以有兩種其它寫法:while ($number =~ s/^(-?\d+)(\d\d\d)/$1,$2/) {1;}和‘keep looping‘ while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/;這個替換做了什么呢?模式會匹配字符串的前面部份,不能匹配小數(shù)點后面的部份。記憶$1會得到"12345",$2會得到"678",因此替換后會使得$number變成"12345,678.90"。如果替換成功,則循環(huán)重新開始。這次,模式不能匹配逗號以后的部份,因此$number變成"12,345,678.90"。這樣,替換在每次通過空循環(huán)時添加一個逗號。接著再進(jìn)入一次循環(huán),但這次模式不能匹配,所以循環(huán)就結(jié)束。在字符開頭的一個負(fù)號作用是把美元符號放在正確的位置。變樣$number就是"$12,345,678.90"。高級排序內(nèi)置的sort操作符按ASCII字母順序排序。如果要對組數(shù)值,或大小寫無關(guān),或存儲在散列中的信息對一些條目進(jìn)行排序。那就要告訴perl你想要什么樣的順序,方法就是寫一個排序定義子例程。如下一個數(shù)值排序子例程:sub by_number {if ($a < $b ) {-1} elsif ($a > $b) {1} else {0}}如果$a應(yīng)該$b之前,則返回-1,如果$b應(yīng)該在$a之前,則返回1,如果$a 和$b的順序無關(guān)緊要,則返回0,如相等。要使用排序子例程,只須把它的名字放在關(guān)鍵字sort操作符和要排序的列表之間就可以了。my @result = sort by_number @some_number;不需在子例程中聲明$a $b,如果這樣做了,子例程就無法工作。還有一種更簡單的寫法,而且更有效率。采用<=>操用符。sub by_number { $a <=> $b}cmp是比效字符串的操作符。sub ascii {$a cmp $b)my @stings = sort ascii @any_string;大小寫無關(guān)的比較sub case_insensitive {"\L$a" cmp "\L$b"} 用\L強制把參數(shù)變成小寫以“內(nèi)聯(lián)”的方式把排序子例程寫進(jìn)代碼中:my @number = sort {$a <=> $b} @some_number;如果按降序排序,可用reverse寫成:my @number = reverse sort {$a <=> $b} @some_number;也可以把參數(shù)互換達(dá)到反序的目的:my @number = sort {$b <=> $a} @some_number;按值排序一個散列my %score =("aa" => 195,"bb" => 201,"cc" => 40);my @winners = sort by_score keys %score;sub by_score { $score{$b} <=> $score{a} }按照多個鍵排序如果散列中有兩個相同的值。那么可以按名字排序。my @winners = sort by_score_and_name keys %score;sub by_score_name { $score{$b} <=> $score{a} 按數(shù)值分?jǐn)?shù)排序or 加一個低優(yōu)先級的短路or操作符$a cmp $b 按名字根據(jù)ASCII字母順序排序}排序子例程不是只能使用兩級排序,允許多級排序。如上例,多加幾個or操作符就可以了。第十六章 簡單數(shù)據(jù)庫DBM文件和DBM散列在每個有perl的系統(tǒng)都有一個已經(jīng)可用的簡單數(shù)據(jù)庫,以DBM文件的形式存在。這可讓你的程序把數(shù)據(jù)存儲在一個文件或一對文件中以便快速查詢。當(dāng)使用兩個文件時,一個存放數(shù)據(jù),一個存放目錄。有些DBM的實現(xiàn)對文件中每個鍵和值的大小有一個1000字節(jié)的限制。但對文件中單個數(shù)據(jù)項的數(shù)目沒有限制,只要你有足夠的硬盤空間。打開和關(guān)閉DBM散列要把一個DBM數(shù)據(jù)庫和一個DBM散列關(guān)聯(lián)起來,即打開數(shù)據(jù)庫,可以使用dbmopen函數(shù)。dbmopen (%DATA,"my_database",0644)or die "cannot create my_database:$!";第一個參數(shù)是散列的名字,如果這個散列已經(jīng)有值了,那么在打開DBM文件后這些值都將無法訪問。第二個參數(shù)是DBM數(shù)據(jù)庫名,在硬盤上通常以一對擴展名為.dir and .pag的文件存儲,但在這里不需要打上擴展名。第三個參數(shù)是權(quán)限值。被賦于打開的文件。使用大寫散列名只是個傳統(tǒng),和文件句柄一樣。DBM散列在程序運行的全過程中一直打開。當(dāng)程序結(jié)束時,關(guān)聯(lián)被終止。你也可以用dbmclose關(guān)閉它dbmclose (%DATA)使用DBM散列DBM散列與一般散列幾乎一樣工作??梢栽谏⒘兄刑砑樱瑒h除,保存數(shù)據(jù)。只是并非存在內(nèi)存中,而是在硬盤上。$DATA("aa") = "test"; 生成或更新一個元素delete $DATA{"aa"}; 刪除數(shù)據(jù)庫中一個元素while (my($key,$value) = each(%DATA)) {print "$key has value of $value\n";}訪問一個由c程序維護(hù)的DBM文件,你就應(yīng)該知道C程序通常會在字符的末尾加一個NUL("\0")字符,原因是c使用NUL字節(jié)作為字符串尾標(biāo)志。DBM庫例程不需要這個NUL,因此NUL會被當(dāng)作數(shù)據(jù)的一部份被存儲。如果要和C程序合作,就必須在你的鍵和值后面加一個NUL字符,而把返回值末尾的NUL去掉從而使得數(shù)據(jù)變得有意義。例如在一個unix系統(tǒng)上的sendmail別名數(shù)據(jù)庫中搜索mymail。你可作以下操作:dbmopen(my %ALL,"/etc/mail/aliases",undef) or die "no aliases?";my $value = $ALL{"mymail\0"}; 注意附加的NUL$value =~ s/\0$//; 刪去結(jié)尾的NULprint "my mail is headed for "$value\n";顯示結(jié)果如果你DBM文件被多個進(jìn)程并發(fā)訪問,如通過WEB來更新,那么就需要一個附加的鎖文件。具體內(nèi)容需查詢相關(guān)資料。在pack and unpack處理數(shù)據(jù)pack函數(shù)取一個格式字符串和一組參數(shù),然后把參數(shù)裝配置到一起構(gòu)成一個字符串,unpack還原字符串。my $buffer = pack ("c s l",31,1123,85858);格式c,s,l代表char,short and logn。所以第一個數(shù)字裝入一個字節(jié),第二個數(shù)字裝入兩個字節(jié),第三個數(shù)字裝入四個字節(jié)。格式字符可查詢perlfunc手冊。固定長度的隨機訪問數(shù)據(jù)庫固定長度不是說文件本身,而是指單個記錄是固定長度的,就好像關(guān)系數(shù)據(jù)庫中的定長字段。假如有一組記錄,用pack格式字符代表如下:名字 40個字符 a40年齡 單字節(jié)整數(shù) C分?jǐn)?shù) 5個雙字節(jié)整數(shù) I5日期 4字節(jié)整數(shù) L每個記錄共55個字節(jié)。perl支持使用此類磁盤文件。步驟如下:1、為讀和寫打開一個磁盤文件。用"+<"模式open一個文件,就對該文件有讀寫權(quán)限?!?lt;”只是有讀權(quán)限?!?>”生成一個新文件,并對它有讀寫權(quán)限。2、在這個文件中移動到任意位置。seek函數(shù)能在文件中移動seek (HEAD,55 * $n,0);第一個參數(shù)是文件句柄。第二個參數(shù)是距文件頭的偏移量,以字節(jié)為單位。第三個參數(shù)是0,是“從哪里開始”參數(shù),如果你尋址到一個相對于當(dāng)前位置的位置,或相對于文件尾的位置,就可使用一個非0值,多數(shù)為0。一旦文件指針用seek定了位,那么下次的輸入輸出操作將會從那個位置開始。3、按長度取出數(shù)據(jù),而不是直到下一個換行符。使用read函數(shù)讀取數(shù)據(jù)。my $buf; 輸入緩沖區(qū)變量my $number_read = read(HEAD,$buf,55)讀出55個字節(jié)數(shù)據(jù)后,可用unpack拆裝它們,以獲得具體信息。my ($name,$age,$score1,$score2,$score3,$score4,$score5,$when) = unpack"a40 C I5 L",$buf;4、按固定長度寫數(shù)據(jù)。不是用write,而是用print。并用pack確保長度正確。以存入一個new_score和時間為例print HEAD pack("a40 C I5 L",$name,$new_scroe,$score1,$score2,$score3,$score4,time);可變長(文本)數(shù)據(jù)庫#!/usr/bin/perl -wuse strictchomp(my $date = `date`); 一個更好的辦法是使用localtime@ARGV = glob "aa.dat" or die "no files found";$^I = ".bak"; 舊文件備份成.bak文件,如果是空串,則不生成備份,但不建議這樣用。while (<>) {s/^aaa:*/aaa:change value/; 修改值s/^bbb:.*\n//; 刪除s/^ccc:.*/ccc:$date/; 更新日期print;}該程序生成一個修改后的新文件,文件名和舊文件一樣,舊文件被備份成.bak文件。該程序能在幾秒鐘內(nèi)更新幾百個文件,功能相當(dāng)強大。從命令行現(xiàn)場編輯# perl -p -i.bak -w -e ‘s/aaa1/aaa/g‘ bbb*.dat-p 告訴perl為你寫一個程序-i.bak 同$^I設(shè)置,生成.bak文件-w 打開警告-e 表示后面是可執(zhí)行代碼最后一個參數(shù)表明@ARGV將包含匹配這個glob文件名列表。一個完整的程序如下:#!/usr/bin/perl -w@ARGV = glob "bbb*.dat";$^I=".bak";while (<>) {s/aaa1/aaa/g‘;print;}如果代碼少,只有幾行,采用命令行選項更方便。第十七章 一些高級Perl技術(shù)用eval捕獲錯誤一種捕獲致命錯誤的辦法,把代碼放在eval塊中。eval { $aa = $cc / $dd }; 這樣,即使$dd是零,也不會導(dǎo)程序崩潰。如果出錯,程序會繼續(xù)運行,并不崩潰,$@變量包含了程序崩潰的出錯信息。如果沒有錯誤,$@為空。它是一個有用的布爾值。print "an error occurred":$@" if $@; 如果出錯,則打印出錯信息。eval 可嵌套eval不能捕獲的問題有四種1、非常嚴(yán)重的錯誤,導(dǎo)致perl本身崩潰。2、eval塊中的語法錯會在編譯時被抓住,不會在$@中返回。3、exit操作符立即終止程序。4、警告信息。用grep從一個列表中選擇條目從一個大的數(shù)字列表中取得奇數(shù)條目。my @number = grep {$_ % 2 } 1..1000;這行簡單的代碼就得到一個500個奇數(shù)的列表。它是如何工作的呢?grep第一個參數(shù)是一個塊,其中$_表示列表中每個條目的占位符,該塊返回一個布爾值。其余的參數(shù)是要搜索的條目列表。grep對列表中的每個條目計算一次表達(dá)式,如果為真就包括到結(jié)果列表中。$_不斷地由列表中的一個元素變成下一個元素。就好像一個foreach循環(huán)。grep是perl中的一個操作符,同unix中的工具名grep同名。能完成相同的工作,但更加強大。下面語句能把文件中提到test的行抓取出來:my @test = grep {/\btest\b/i} <file>;如果你選擇的僅僅是一個簡單的表達(dá)式,而不是一個完整的塊,可以不用大括號,用一個逗號隔開就可以了。my @test = grep /\btest\b/i,<file>;用map轉(zhuǎn)換一個列表的條目與grep相似,對列表中的每個條目都計算一次塊,但塊的最后一個表達(dá)式不同,它實際上成為結(jié)果列表的一部份。my @date = (4.22,4,33,5.323,78.2);my @formatted_date = map {&big_money($_)} @date;不加引號的散列鍵如$score {aa},而不必寫成$score {"aa"}這類不帶引號的簡單字符串被稱為裸字(bareword)。前提是大括號中除了裸字外沒有其它東西。更強大的正則表達(dá)式非貪婪數(shù)量符我們在第八章中見到的四個數(shù)量符都是貪婪(greedy)的。意思是它們都盡可能多地進(jìn)行匹配。+? 匹配一次或多次,和加號一樣,但它傾向于匹配盡量少的次數(shù)。*? 匹配0次或多次,和*號一樣,但它傾向于匹配最少的次數(shù)。在html中去掉所有的<bold>and </bold>標(biāo)記如果寫成:s#<bold>(.*)</bold>#$1#g就不對,因為星號是貪婪的,如果文件中我多個這樣的標(biāo)記,它可能匹配第一個的<bold>和最后一個的</bold>。{3,10}??? 匹配一次或0次。匹配多行文本傳統(tǒng)的正則表達(dá)式只能用來匹配單行文本,perl可以匹配多行文本,用/m匹配內(nèi)部換行符的位置。切片我們會碰到只操作一個給定列表中幾個元素的情況,例如一個圖書館讀者的信息,文件中每行用六個冒號分隔。但我只需要其中的兩個信息,這時我們就可以用切片的方法來處理:while (<FILE>) {chomp;my @items = split /:/;my($aa,$bb) = ($items[1],$items[5]);....}可以直接寫成my $aa = (split /:/)[1];my $bb = (split /:/)[5];也可以更高效和簡單地寫成my ($aa,$bb) = (split /:/)[1,5];切片是從列表中取出幾個項目最簡單的方法。數(shù)組切片my @numbers =@names [1,2,3,4,9];散列切片my @three_scores = @scores{qw/aa bb cc/};