perl一行式程序系列文章:Perl一行式html
對於Perl的一行式perl程序來講,選擇要輸出的、要刪除的、要插入/追加的行是很是容易的事情,由於print/say決定行是否輸出/插入/追加/刪除。雖然簡單,但對於普遍應用在sed的示例仍是能夠拿到這裏來討論一番。正則表達式
由於輸出/刪除/插入/追加行都是經過print/say在不一樣條件下的操做,因此本文只會介紹輸出操做,刪除/插入/追加其實都是一樣的原理。數組
$ perl -lne 'print;exit' file.log
$ perl -ne 'print if $. == 13' file.log
$ perl -ne 'print if $.<=10' file.log $ perl -ne 'print if 1..10' file.log $ perl -ne '$. <= 10 && print' file.log $ perl -ne 'print; exit if $. == 10' file.log
$ perl -ne '$last=$_;END{print $last}' file.log
或者經過文件結尾eof來判斷:less
$ perl -ne 'print if eof' file.log
這裏的eof函數的做用是:若是下一行讀取到了文件尾部eof,就返回1。不然函數
這個實現起來可能稍顯複雜,但邏輯很簡單:向一個數組中添加10行元素,若是數組元素個數超過了10,則剔除數組的第一個元素。code
$ perl -ne ' push @lines,$_; if(@lines>10){ shift @lines; } END{ print @lines } ' /etc/passwd
這裏是shift一個元素來保證"窗口"的穩定性:最多隻有10個元素。另外一種穩妥的方式是直接切片,從數組中取最後10個元素:regexp
$ perl -ne ' push @lines,$_; @lines = @lines[@lines-10..$#lines] if @lines>10; END{print @lines} ' /etc/passwd
有了前一個示例做爲基礎,這個需求很容易實現。htm
保留一個11行元素的數組,最後輸出前10個元素便可。blog
$ perl -ne ' push @a,$_; shift @a if @a>11; END{print @a[0..$#a-1]} ' /etc/passwd
這個很簡單,只需判斷行號的奇偶性便可。get
$ perl -ne 'print if $. % 2 == 0' file.log $ perl -ne 'print unless $. % 2' file.log
$ perl -ne 'print if /regexp/' file.log
$ perl -ne 'print if /regexp1/../regexp2/' file.log
只需將每行保留到變量中,若是當前行匹配了,則輸出上一行保存的值。
$ perl -ne '/regexp/ && $last && print $last;$last = $_' file.log
若是想要輸出匹配的前M行,只需把這些數量的行保存到數組中,並不斷地shift剔除就能夠。
$ perl -ne '$p && print; $p = /regexp/' file.log
Perl中正則表達式的匹配操做返回的是成功與否的布爾真假,因此$p = /regexp/
表示若是匹配了,則$p
的值爲真,不然爲假。
若是$p
爲真,則下一行將被輸出,且繼續對輸出行進行匹配,若是輸出行仍然能匹配,則繼續輸出下一行。
上面的過程能夠改寫成邏輯更爲清晰的一行式:
$ perl -ne 'if($p){print;$p=0}++$p if /regexp/' file.log
上面的$p
是一個狀態標記變量,若是匹配成功,就標記爲真值,並在輸出的時候重置狀態變量。
還能夠採用另外一種處理邏輯:本身編寫從<>
讀取行的while循環,若是匹配了就繼續讀入下一行。由於讀入的下一行可能繼續匹配,因此在while循環中使用redo邏輯回到while循環的開頭。
$ perl -se ' while(<>){ if(/$reg/){ if(eof){ exit; } print $_ = <>; } redo if /$reg/; } ' -- -reg="REGEXP" file.log
上面採用狀態標記變量$p
,這個狀態標記變量能夠更深刻地使用。
若是匹配了,則$p
設置爲5,而後輸出後面的行時對$p
自減。
$ perl -ne ' if($p){print;$p--} if(/regexp/){$p = 5;print}; ' file.log
$ perl -ne ' next if "$line" eq "$_"; print $line = $_; ' file.log