grep由两个关键线分隔的文本块

时间:2013-11-12 10:27:29

标签: grep match textblock

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

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

Beginning of block
...
... etc.

块可以有任意数量的行,但始终以两个分隔符开头。我想做的是匹配“some_pattern”并将整个块打印到stdout。通过上面的例子,我只会得到这个:

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

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

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

知道怎么用grep做这个吗? (或者可能使用其他工具)

5 个答案:

答案 0 :(得分:9)

我猜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,则会打印已存储的所有行。最后清除[]并重置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

答案 1 :(得分:4)

以下内容可能适合您:

sed -n '/Beginning of block/!b;:a;/End of block/!{$!{N;ba}};{/some_pattern/p}' filename

答案 2 :(得分: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

答案 3 :(得分:0)

sed -n "
/Beginning of block/,/End of block/ {
   N
   /End of block/ { 
      s/some_pattern/&/p
      }
   }"

sed对于这种治疗是有效的

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

答案 4 :(得分:0)

不知道我是否错过了什么,但这是上述答案之一的更简单的变化:

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}'```