如何 grep 查找包含多行特定单词的文本块?我怎样才能从 tail -f 管道做到这一点?

如何 grep 查找包含多行特定单词的文本块?我怎样才能从 tail -f 管道做到这一点?

我想跟踪日志文件并仅打印与正则表达式模式匹配的文本块.*\n.*\nABC(.*\n){1-6}XYZ。如果我的正则表达式已经错误,我想匹配这个例子:

TIMESTAMP HERE
LOG ENTRY HEADER
ABC
STUFF
...
STUFF
XYZ

或者我会怎样真的like 是仅当字符串“ZZZ”没有出现在匹配中的任何地方时才匹配上面的内容。

我的解决方案是执行以下操作:

tail -f file | egrep --line-buffered -B 2 -A 6

但显然这回报比我想要的要多得多。我也没有安装软件包的选项,但我确实有awk并且sed可用。

答案1

您可以选择从“TIMESTAMP”到“XYZ”的任何块,并通过 在块后面引入 NUL 作为分隔符sed,然后通过其他工具筛选出来,例如grep最后删除 NUL 字节:

tail -f file |
  sed -n '/TIMESTAMP/,/XYZ/{/XYZ/s/$/\x00/;p}' |
  grep -z 'ABC' |
  grep -z -v 'ZZZ' |
  tr -d '\x00'

答案2

您可以做的是确定开始和结束模式。例如,让我们使用TIMESTAMP HEREandXYZ来达到此目的,并使用 sed 来查找之间的所有行。

sed -n '/^TIMESTAMP HERE/,/^XYZ/p' logfile.txt

答案3

更新:

tail -f log | sed '/\n/!N;N;/\nABC$/!D;N;N;N;N;N;N;/ZZZ/d'

显示与模板匹配的行ABC,如果没有模板,则显示前面 2 行和后面 6 行ZZZ

缓冲区中始终有 3 行。我们检查最后一项。如果没有匹配项,则删除第一个并将执行移至脚本的开头。如果有匹配,则再添加 6 行。打印的决定是根据模式进行匹配而做出的ZZZ

不匹配
假设XYZ模式必须匹配记录块的末尾。然后:

tail -f | sed ':1;N;/XYZ/!b1;/ZZZ/d'

我认为这里不需要无缓冲输出,但是-u标志在sed流编辑器中提供了此功能。

还可以输入记录块开头的模式:

tail -f | sed '/TIMESTAMP/!d;:1;N;/XYZ/!b1;/ZZZ/d'

上述脚本将从记录开始到结束的所有行添加到SED编辑器缓冲区(模式空间)中,并与模板进行匹配ZZZ,从而确定删除整个记录或打印。

另一种选择是,如果日志块包含相同数量的行,那么可以按照您尝试使用egrep 时的需要精确地对它们进行计数和显示。
让我们选择加号 + 符号作为计数器。在此示例中,我们将数到 5,但您可以在此模板中更改它 - +\{5\}

tail -f log | sed ':1;x;s/$/+/;/+\{5\}/!{x;N;b1};s/.*//;x'

还可以通过模板添加帐号开头并删除:

tail -f log | sed '/TIMESTAMP/!d;:1;x;s/$/+/;/+\{5\}/!{x;N;b1};s/.*//;x;/ZZZ/d'

计数器的工作原理是这样的。 SED 编辑器有两个缓冲区 - 模式空间和保持空间。该字符串被写入模式空间。该x命令更改两个缓冲区的内容,我们在保留空间的末尾写入一个加号,并检查它们的编号,如果模式匹配 5 则打印内容,否则我们添加下一行并增加计数器。 5 行匹配后,我们重置计数器并重复该过程。

相关内容