【问题标题】:Unix one-liner to match 2 sections of a fileUnix 单行匹配文件的 2 个部分
【发布时间】:2014-10-03 04:50:56
【问题描述】:

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

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 个有限部分,其间有有限间隙,它将终止。

【问题讨论】:

  • 你的预期输出是什么?
  • 您的一个集合案例的代码不会打印集合的第一行。
  • @Barmar 正确。我可以接受,只要它打印出每组的大部分内容 - 实际上比赛的开始和结束线并不重要。
  • 这个sed -n '/mypattern/p' file
  • 您不希望打印第三组(如果有的话)?或者没有发生这种情况,所以 Avinash Raj 套件的行很好地满足了要求

标签: bash unix sed


【解决方案1】:

这会计算匹配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 的行,如果这是组中的第一行,即f==0,则组计数器c 会递增。然后将f 设置为 1,表示我们现在在一个组中。该行被打印。 next 命令告诉awk 跳过所有剩余的命令并从下一行重新开始。

  • f=0

    如果我们得到这个语句,这意味着我们在一个组之外,因此组标志 f 被设置为零。

  • c==2{exit}

    如果我们得到这个声明,我们就在一个组之外,如果c==2,我们已经看到了两个完整的组。因此,我们exitawk。

【讨论】:

    【解决方案2】:

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

    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)
    

    【讨论】:

      【解决方案3】:

      这可能对你有用(GNU sed):

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

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

      或以编程方式:

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

      【讨论】:

        【解决方案4】:

        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
        

        【讨论】:

          猜你喜欢
          • 2017-12-21
          • 1970-01-01
          • 1970-01-01
          • 2012-02-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多