Perl一行式:選擇行輸出、刪除、追加、插入


perl一行式程序系列文章Perl一行式


對於Perl的一行式perl程序來說,選擇要輸出的、要刪除的、要插入/追加的行是非常容易的事情,因為print/say決定行是否輸出/插入/追加/刪除。雖然簡單,但對於廣泛應用在sed的示例還是可以拿到這里來討論一番。

因為輸出/刪除/插入/追加行都是通過print/say在不同條件下的操作,所以本文只會介紹輸出操作,刪除/插入/追加其實都是同樣的原理。

輸出第一行

$ perl -lne 'print;exit' file.log

輸出第13行

$ perl -ne 'print if $. == 13' file.log

輸出前10行

$ 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來判斷:

$ perl -ne 'print if eof' file.log

這里的eof函數的作用是:如果下一行讀取到了文件尾部eof,就返回1。否則

輸出倒數10行

這個實現起來可能稍顯復雜,但邏輯很簡單:向一個數組中添加10行元素,如果數組元素個數超過了10,則剔除數組的第一個元素。

$ perl -ne '
    push @lines,$_;
    if(@lines>10){
        shift @lines;
    }
    END{
        print @lines
    }
    ' /etc/passwd

這里是shift一個元素來保證"窗口"的穩定性:最多只有10個元素。另一種穩妥的方式是直接切片,從數組中取最后10個元素:

$ perl -ne '
    push @lines,$_;
    @lines = @lines[@lines-10..$#lines] if @lines>10;
    END{print @lines}
    ' /etc/passwd

輸出倒數第11行到倒數第2行

有了前一個示例作為基礎,這個需求很容易實現。

保留一個11行元素的數組,最后輸出前10個元素即可。

$ perl -ne '
    push @a,$_;
    shift @a if @a>11;
    END{print @a[0..$#a-1]}
    ' /etc/passwd

輸出文件的第偶數行

這個很簡單,只需判斷行號的奇偶性即可。

$ 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

輸出匹配行及其后5行

上面采用狀態標記變量$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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM