仅打印与模式匹配的每行之前的第 N 行

仅打印与模式匹配的每行之前的第 N 行

我试图仅打印<N>搜索模式之前的第 th 行。打印搜索模式之前的grep -B<N>所有行。<N>我看到了 awk 代码这里只能打印<N>搜索模式后的第 3 行。

awk 'c&&!--c;/pattern/{c=N}' file

如何修改它以仅打印<N>每行匹配之前的第 th 行pattern?例如,这是我的输入文件

...
...
   0.50007496  0.42473932  0.01527831
   0.99997456  0.97033575  0.44364198
Direct configuration=     1
   0.16929051  0.16544726  0.16608723
   0.16984300  0.16855274  0.50171112
...
...
   0.50089841  0.42608090  0.01499159
   0.99982054  0.97154975  0.44403547
Direct configuration=     2
   0.16931296  0.16553376  0.16600890
   0.16999941  0.16847055  0.50170694  
...

我需要一个可以返回2nd line搜索字符串之前的命令Direct configuration。我正在尝试运行这个SUSE Linux

答案1

需要使用行缓冲区。

尝试一下这个:

awk -v N=4 -v pattern="example.*pattern" '{i=(1+(i%N));if (buffer[i]&& $0 ~ pattern) print buffer[i]; buffer[i]=$0;}' file

将值设置N为要打印的图案之前的第 N 行。

pattern将值设置为要搜索的正则表达式。

buffer是一个元素数组N。它用于存储线路。每次找到该模式时,N都会打印该模式之前的第 3 行。

答案2

该代码不适用于前面的行。要获取匹配模式之前的行,您需要以某种方式保存已处理的行。由于awk只有关联数组,我想不出一种同样简单的方法来执行您想要的操作awk,因此这是一个 perl 解决方案:

perl -ne 'push @lines,$_; print $lines[0] if /PAT/; shift(@lines) if $.>LIM;' file 

更改PAT为您想要匹配的模式和LIM行数。例如,要在每次出现 之前打印第 5 行foo,您可以运行:

perl -ne 'push @lines,$_; print $lines[0] if /foo/; shift(@lines) if $.>5;' file 

解释

  • perl -ne:逐行读取输入文件并将给定的脚本应用于-e每一行。
  • push @lines,$_:将当前行( $_)添加到数组中@lines
  • print $lines[0] if /PAT/:如果当前行与所需模式匹配,则打印数组中的第一个元素@lines( )。$lines[0]
  • shift(@lines) if $.>LIM;:$.是当前行号。如果大于限制,则从数组中删除第一个值@lines。结果是@lines总是有最后LIM几行。

答案3

tac file | awk 'c&&!--c;/pattern/{c=N}' | tac

但是,当 N 行内有多个匹配项时,这与“转发”用例具有相同的遗漏。

当输入从正在运行的进程通过管道传输时,它不会很好地工作,但当输入文件完整且不增长时,这是最简单的方法。

答案4

与 的替代方式sed

为了N=1:

sed '$!N; /.*\n.*pattern/P; D' FILE

为了N=2

sed '1N; $!N; /.*\n.*\n.*pattern/P; D' FILE

为了N=2情况下,第一行将读取下一行N-1模式空间中的行然后开始一个N;P;D循环 - 读取另一行,如果模式空间中的最后一行匹配,则打印模式空间中的第一行然后删除它,开始一个新的循环。

缺点是需要针对不同的值进行修改:

为了N=3:

sed '1{N;N}; $!N; /.*\n.*\n.*\n.*pattern/P; D' FILE

为了N=4:

sed '1{N;N;N}; $!N; /.*\n.*\n.*\n.*\n.*pattern/P; D' FILE

所以它很快就会变得很麻烦,尽管对于更大的值您可以准备一个脚本文件并将其传递给sed

相关内容