【问题标题】:grep 3 latest occurences and some lines around the occurencegrep 3 个最新事件和事件周围的一些行
【发布时间】:2017-11-13 11:32:36
【问题描述】:

我有一个类似的文件:

exception: anythinggggg...
exception: anythinggggg...
abchdhjsdhsd
ygsuhesnkc
exception: anythingggg...
exception: anything...
..
..

我想 grep 最近 2 次出现的异常关键字以及它之前的 3 行和之后的 3 行。

我正在使用类似的东西

grep -C 3 exception | tail -12

我在这里使用 tail -12,因为我希望每次出现 6 行,最近出现 2 行。当异常的发生彼此相距很远时,这可以正常工作,但是如果说两次发生都是连续的,这会给我带来无用的行。

abdgjsd
abdgjsd
abdgjsd
abdgjsd
abdgjsd
abdgjsd
abdgjsd
abdgjsd
exception
exception
exception
abcd

在上述情况下,它给了我

abdgjsd
abdgjsd
abdgjsd
exception
exception
exception
abcd

然而,我想要的是

abdgjsd
exception
exception -----------------> OUTPUT FOR FIRST OCCURRENCE
exception
abcd

abdgjsd
abdgjsd
exception-----------------> OUTPUT FOR SECOND OCCURRENCE
exception
exception
abcd

还有其他方法吗?可能我还可以指定出现的次数,而不仅仅是 grep 行和尾随它的一些输出。

【问题讨论】:

  • 请在您的问题中添加示例输入和所需的输出示例输入。
  • 问题中已经指定了..

标签: perl unix grep tail


【解决方案1】:

您得到的输出是因为 grep 在下一次匹配时停止打印上下文 (-C)。我不知道如何让它表现得不一样。

下面的脚本(写在命令行上)读取整个文件并形成一个行数组。然后它遍历它并为每个匹配打印围绕两行,或者直到数组的开始/结束。

perl -MList::Util=min,max -0777 -wnE'
    @m = split /\n/; 
    for (0..$#m) { 
        if ($m[$_] =~ /exception/) { 
            $bi = max(0,$_-2); 
            $ei = min($_+2, $#m);
            say for @m[$bi..$ei]; 
            say "---" 
         } 
     }
' input.txt

打印--- 以便于查看输出。这将打印所需的输出。

-0777 选项将整个文件slurp 放入$_ 变量中,即split 换行符。迭代遍历数组索引($#m@m 的最后一个元素的索引)。 $bi$ei 是要打印的开始/结束索引,在数组的开头和结尾附近不能是 +/- 2。

输出可以通过管道传送到tail,但这不能自动进行:如果匹配在最后两行内,则输出行将减少(一或两行),因此需要知道输入以进行精确剪切-离开。或者在脚本中查找匹配索引@idx = grep { $m[$_] =~ /exception/} for 0..$#m;,并在条件中使用它来仅打印最后两个。

如果你要使用这样的东西,我会把它做成一个脚本。然后直接将所有行读入数组,提供命令行选项(如grep中的-C)等

维护逐行处理会使工作变得更加复杂。我们需要跟踪匹配,以便在读取以下行后打印它们。但是这里我们需要多个这样的记录——如果它们在下面要打印的行中,那么对于下一个匹配项也是如此。

【讨论】:

  • @Zaid 谢谢,是的,非常相关!这里有个小问题是关于第 0,1 行和 -2,-1 行的匹配。至于只通过一次而不是拉动整个文件——另一个很好的答案在这里不起作用,因为我们需要多个缓冲区(或索引计数器),这就是我所说的“更复杂"
  • 我对我和你的答案都有一个抱怨:​​如果匹配发生在连续的行上,则会打印重复的行。在这里可能没问题,但我的纯粹主义者说在这种情况下应该扩展相同的上下文
  • @Zaid 好吧,我同意。我认为grep对此的解决方案是相当合理的;至少没有重复。然而,这个问题正是关于这一点的——他们想要重复输出,他们每次都想要整个上下文。我也可以理解,但我也不会那样设计通用工具,同意。
【解决方案2】:

这是一个开始:

$ cat tst.awk
BEGIN { bufSize = 5 }
{ updBuf(NR) }
/exception/ { rangeEndNrs[NR+int(bufSize/2)] }
NR in rangeEndNrs { prtBuf(NR) }
END { prtBuf(NR+1) }

function updBuf(nr) {
    buf[((nr-1)%bufSize)+1] = $0
}

function prtBuf(nr,     i) {
    for (i=1; i<=bufSize; i++) {
        print buf[((nr+i-1)%bufSize)+1]
    }
    print "---"
}

.

$ awk -f tst.awk file
abdgjsd
abdgjsd
exception
exception
exception
---
abdgjsd
exception
exception
exception
abcd
---
exception
exception
exception
abcd
abdgjsd
---

它的工作原理是只保留一个 5 行的输入行缓冲区,并且在任何发现“异常”的地方设置一个指示符,指示应该在 2 行之后打印缓冲区,从而打印“异常”行加上前后的 2 行它。您只需要对其进行按摩以处理距输入文件的开头或结尾不到 2 行的“异常”情况,但是您希望处理它(请参阅上面的最后一个输出块,可能是不希望的,环绕缓冲区因为它在输入文件的末尾运行)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多