Perl一行式:选择行输出、删除、追加、插入

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


对于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来判断:less

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

这里的eof函数的做用是:若是下一行读取到了文件尾部eof,就返回1。不然函数

输出倒数10行

这个实现起来可能稍显复杂,但逻辑很简单:向一个数组中添加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

输出倒数第11行到倒数第2行

有了前一个示例做为基础,这个需求很容易实现。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

输出匹配行及其后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
相关文章
相关标签/搜索