6

我有一个文本文件,其中包含大致格式如下的文本块:

Beginning of block
...
...
...
.........some_pattern.......
...
...
End of block

Beginning of block
...
... etc.

块可以有任意数量的行,但总是以两个分隔符开头。我想做的是匹配“some_pattern”并将整个块打印到标准输出。对于上面的例子,我只会得到这个:

Beginning of block
...
...
...
.........some_pattern.......
...
...
End of block

我尝试过这样的事情但没有成功:

grep "Beginning of block\n.*some_pattern.*\n.*End of block"

知道如何使用 grep 执行此操作吗?(或者可能使用其他工具)

4

5 回答 5

10

我想awk这更好:

awk '/Beginning of block/ {p=1};
     {if (p==1) {a[NR]=$0}};
     /some_pattern/ {f=1};
     /End of block/ {p=0; if (f==1) {for (i in a) print a[i]};f=0; delete a}' file

解释

p它只是在标志“活动”并且some_pattern匹配时打印:

  • 当它找到时Beginning of block,然后生成变量p=1并开始将行存储在数组中a[]
  • 如果找到some_pattern,则将标志设置f为 1,以便我们知道已找到该模式。
  • 当它找到End of block它时,它会重置p=0。如果some_pattern自上次以来已找到Beginning of block,则打印所有已存储的行。最后 a[] 被清除, f 被重置;当我们再次相遇时,我们将有一个新的开始Beginning of block

其他测试

$ cat a
Beginning of block
blabla
.........some_pattern.......
and here i am
hello
End of block

Beginning of block
...
... etc.
End of block
$ awk '/Beginning of block/ {p=1}; {if(p==1){a[NR]=$0}}; /some_pattern/ {f=1}; /End of block/ {p=0; if (f==1) {for (i in a) print a[i]}; delete a;f=0}' a
Beginning of block
blabla
.........some_pattern.......
and here i am
hello
End of block
于 2013-11-12T10:29:56.377 回答
7

以下可能对您有用:

sed -n '/Beginning of block/!b;:a;/End of block/!{$!{N;ba}};{/some_pattern/p}' filename
于 2013-11-12T10:49:42.150 回答
1

这是一种使用方法awk

awk '/Beginning of block/ { r=""; f=1 } f { r = (r ? r ORS : "") $0 } /End of block/ { if (f && r ~ /some_pattern/) print r; f=0 }' file

结果:

Beginning of block
...
...
...
.........some_pattern.......
...
...
End of block
于 2013-11-12T11:48:20.547 回答
1

不确定我是否遗漏了一些东西,但这是上述答案之一的更简单的变体:

awk '/Beginning of block/ {p=1}; 
     /End of block/ {p=0; print $0}; 
     {if (p==1) print $0}'

您需要在End of Block案例中打印输入行以获取两个分隔符。

我想要一个不打印分隔符的轻微变化。在 OP 的问题中,分隔符模式简单而独特。然后最简单的方法是通过管道输入| grep -v block. 我的情况更不规则,所以我使用了下面的变体。请注意该next语句,因此第三个语句不会打印开始块:

awk '/Beginning of block/ {p=1; next}; 
     /End of block/ {p=0}; 
     {if (p==1) print $0}'
于 2020-10-12T23:31:37.323 回答
0
sed -n "
/Beginning of block/,/End of block/ {
   N
   /End of block/ { 
      s/some_pattern/&/p
      }
   }"

sed 对于这种处理是有效的

使用 grep,您当然应该通过中间文件或数组。

于 2013-11-12T11:25:57.827 回答