提取第 n 行匹配模式和接下来的 N 行

提取第 n 行匹配模式和接下来的 N 行

有一个大文件,其中包含在文件中定期重复的模式,我想在出现某些值以及下一个值后仅提取特定模式行。
这是一个例子,但之前的数字members of the group实际上并不存在。

输入:

1 members of the group
...
...
2 members of the group
...
...
...
n members of the group
...
...
...

输出:

85 members of the group
...
...
...
...
...

(第 85 场比赛和接下来的 5 行)

答案1

这里有一种方法awk

awk -vN=85 -vM=5 'BEGIN{c=0}
/PATTERN/{c++
{if (c==N) {l=NR;last=NR+M}}
}{if (NR<=last && NR>=l) print}' infile

哪儿Nth 行匹配PATTERNM是后面的行数。它设置一个计数器,当遇到第 3 行匹配时,它会保存行号。然后它打印从当前NRNR+ 的行中号


根据记录,这就是使用sed(gnu sed语法) 的方法:

sed -nE '/PATTERN/{x;/\n{84}/{x;$!N;$!N;$!N;$!N;$!N;p;q};s/.*/&\n/;x}' infile

这是利用保持空间来计数。
每次遇到匹配的行时PATTERN,ex都会更改缓冲区并检查是否有N-1\n保持缓冲区中出现ewline 字符。如果检查成功,它会x再次更改,拉入下一个中号使用$!N命令并p打印模式空间,然后quits。
否则,它只是将另一个\newline char 添加到保留空间,然后 ex变回来。
该解决方案不太方便,因为它很快就会变得很麻烦中号是一个很大的数字,需要一些printf-fu 来构建sed脚本(更不用说模式和使用一些seds 来保持空间限制)。

答案2

(exec <file.txt; grep -m 85 'PATTERN' | tail -n 1; head -n 5)

显然,您可以根据需要调整数字。

man grep

   -m NUM, --max-count=NUM
          Stop reading a file after NUM matching lines.  If the  input  is
          standard  input  from a regular file, and NUM matching lines are
          output, grep ensures that the standard input  is  positioned  to
          just  after the last matching line before exiting, regardless of
          the presence of trailing context lines.  This enables a  calling
          process  to resume a search.

上面的命令通过使用子 shell 并将 STDIN 设置为您想要的文件来利用此功能grep,以便此功能可以正常工作。然后,您可以简单地使用 捕获最终(第 85 个)实例tail -n 1,并通过单独调用 来获取所需的上下文行head

如果您使用此命令知道该文件至少有 85 个实例PATTERN;在这种情况下它将完美地工作。

如果它可能少了,命令就需要一些调整;在当前状态下,如果匹配项少于您所请求的数量,它将简单地打印最终匹配项,而不会出现尾随上下文行。

答案3

主要不了解awk和使用sed正则表达式的东西,我会这样做:

  • 用于grep查找模式,包括行号 ( -n)
  • 使用headtail(或sed)获得第 85 个匹配项(参见这里
  • 使用隔离出行号 Ncut
  • 再次使用headand tail(或sed) 获取原始文件的第 N 行和后续 5 行

所有这些都可以合并为一行。很脏,可能很慢,但可以使用最少的工具集工作。

例子

以下内容搜索 rkhunter.log 文件并显示“basename”的第三个匹配项以及后续四行:

 /var/log$ tail rkhunter.log -n +$(grep -n 'basename' rkhunter.log|cut -d: -f1|tail -n +3|head -1)| head -5

编辑

刚刚看到@Wildcard的答案,切换-m确实grep比我原来的解决方案更容易使用。所以这是另一个使用的答案grep -m

/var/log$ grep -m 3 -A 4 'basename'  rkhunter.log | tail -5

答案4

这在我的 bash 中有效:

{ T=85; N=5; c=0; while read line ; do echo "$line" | grep -c "members of the group" > /dev/null && c=$(($c+1)) ; [[ $c -eq $T ]] && { echo "$line"; break ;} ; done ; head -n $N ; } < input_file

相关内容