如何在 tail -f 时仅打印 grep 的一个匹配项?

如何在 tail -f 时仅打印 grep 的一个匹配项?

我正在阅读活动日志并尝试接听一些特殊电话

$ tail -f example.log | egrep 'pattern1|pattern2|pattern3|pattern4|pattern5'

但有几个图案几乎没有打印(由于开发流程),而其他图案则非常连续地打印。

我怎样才能egrep只打印每个模式的一个请求,以便我可以轻松地看到它们工作得很好。

答案1

你可以这样做:

tail -f example.log | awk '
  BEGIN {
    n = split("pattern1,pattern2,pattern3,pattern4,pattern5", pats, /,/)
  }
  {
    found=0
    for (i in pats) if ($0 ~ pats[i]) {
      found=1
      delete pats[i]
      n--
    }
  }
  found {print; if (!n) exit}'

请注意,awk一旦看到所有模式就会退出,但tail只有在下次写入内容时才会退出(SIGPIPE)。

或者,如果行可能不匹配多个模式,并且如果您不关心找到所有模式后退出,则更短但效率较低:

awk '/pattern1/&&!a++ || /pattern2/&&!b++ || /pattern3/&&!c++ || \
     /pattern4/&&!d++ || /pattern5/&&!e++'

zshGNU grep

(trap '' PIPE;tail -f example.log > >(grep -m1 pattern1) \
                                  > >(grep -m1 pattern2) \
                                  > >(grep -m1 pattern3) \
                                  > >(grep -m1 pattern4) \
                                  > >(grep -m1 pattern5))

但请注意,匹配多个模式的行将被打印多次。

答案2

我相信您之后-o只会打印匹配的部分。然后你可以执行以下操作:

cat example.log | egrep -o 'pat1|pat2|pat3|pat4|pat5' | sort | uniq

如果输出包含模式,那是因为至少有一行与该模式匹配。如果输出包含全部 5 个模式,则每个模式至少匹配一行。

不适用于可以匹配不同字符或不同长度匹配的正则表达式。

答案3

另一种方法可能是在其自己的行上输出与前一个模式匹配的每个模式的行,如下所示:

#! /bin/sh -
tput rmam # no line wrap for terminals that can do it
awk -v u="$(tput cuu1)" -v el="$(tput el)" '
  BEGIN {
    for (n = 0; n < ARGC; n++) pat[n] = ARGV[n]
    ARGC=0
  }
  {
    pre = ""; post = el "\r" u
    for (i = 1; i < n; i++) {
      if ($0 ~ pat[i]) print pre $0 post
      pre = pre "\n"
      post = post u
    }
  }
  END{printf "%s", pre}' "$@"
tput smam

称为:

tail -f example.log | that-script pattern1 pattern2...

例子:

在此输入图像描述

相关内容