Unix one-liner匹配文件的2个部分

时间:2014-10-03 04:50:57

标签: bash unix sed

我有一个类似这样的日志文件:

blah blah
blah
blah mypattern blah
blah mypattern blah
blah
blah mypattern blah
blah mypattern blah
blah

我想要一个单行程序从标准输入读取上述内容(即一次通过),用mypattern打印2组行,然后在打印第二组行后直接退出。

如果我只想要一组线,我使用以下单线:

sed '1,/mypattern/d' |sed '/mypattern/!q'

正如你所看到的,这里或那里的一行没什么大不了的。

编辑:这大致是我预期的输出

blah mypattern blah
blah mypattern blah
blah mypattern blah
blah mypattern blah

如果在边界的任何一侧添加或错过一条线,这不是什么大不了的事。重要的是,对于无限输入,如果模式有2个有限部分,则它将终止,其间存在有限的间隙。

4 个答案:

答案 0 :(得分:2)

这将计算匹配mypattern的行组数,并在第二组结束后退出。因此,即使日志文件是无限的,该命令也将终止。

awk '/mypattern/{c+=!f;f=1;print;next} {f=0} c==2{exit}' logfile

说明:

代码有两个变量:f是一个标志,c是一个计数器。

  • /mypattern/{c+=!f;f=1;print;next}

    f是一面旗帜。当我们在匹配mypattern的一组线之外时,它是零,当我们在里面时,它是一个。

    对于匹配mypattern的任何行,如果这是组中的第一行,即c,则组计数器f==0会递增。然后将f设置为1表示我们现在在一个组中。该行已打印。 next命令告诉awk跳过任何剩余的命令并从下一行重新开始。

  • f=0

    如果我们接到这个陈述,那意味着我们在一个群组之外,因此群组标志f被设置为零。

  • c==2{exit}

    如果我们接到这个陈述,我们就在一个小组之外,如果c==2,我们已经看到了两个完整的小组。因此,我们exit awk。

答案 1 :(得分:1)

技术上是一个单行,但可能不像你想要的那样简洁。从好的方面来说,结果是准确的。

awk 'BEGIN { c=0; s=0; } /mypattern/ { if (!s) c++; s=1; print($0); next; } /./ { if (c >= 2) exit; s=0; }'

通过以下测试:

#!/bin/bash -eu

function mkinput {
    for i in $(seq $1)
    do
        hexdump /dev/urandom | head -n $((1 + $RANDOM % 10))
        for j in $(seq $((1 + $RANDOM % 10)))
        do
            echo "blah mypattern blah (i = $i, j = $j)"
        done
    done
    # Produce an infinite stream of input.
    hexdump /dev/urandom
}

mkinput 10 | awk 'BEGIN { c=0; s=0; } /mypattern/ { if (!s) c++; s=1; print($0); next; } /./ { if (c >= 2) exit; s=0; }'

可能的输出:

blah mypattern blah (i = 1, j = 1)
blah mypattern blah (i = 1, j = 2)
blah mypattern blah (i = 1, j = 3)
blah mypattern blah (i = 2, j = 1)
blah mypattern blah (i = 2, j = 2)

答案 2 :(得分:0)

这可能适合你(GNU sed):

sed -n '/mypattern/{:a;p;n;//ba;x;s/^/x/;/xx/q;x}' file

-n性质使用grep-like选项。过滤mypattern并使用保留空间作为何时退出处理的计数器。

或以编程方式:

sed -n '/mypattern/{:a;p;n;//ba;H;x;s/\n/&/2;x;T;q}' file

答案 3 :(得分:0)

Perl,相当长衬,未经测试

perl -ne 'if (m/mypattern/) { $cnt++ unless $in; $in=1; print; } else { $in=0; exit if $cnt == 2; }'

扩展和适当的Perl"版本以便更好地理解:

my $cnt=0;
my $in=0;
while (<>) {
    if m/mypattern/ {
        $cnt++ unless $in;
        $in = 1;
        print;
    } else {
        $in = 0;
        exit if $cnt == 2;
    }
}

更新:使用

进行测试
aa
aa mypattern aa 1
aa mypattern aa 1
aa mypattern aa 1
aa
aa
aa mypattern aa 2
aa
aa mypattern aa 3
aa mypattern aa 3
aa mypattern aa 3
aa

返回

aa mypattern aa 1
aa mypattern aa 1
aa mypattern aa 1
aa mypattern aa 2