根据开始模式和结束模式之间的模式获取开始模式和结束模式之间的文本

根据开始模式和结束模式之间的模式获取开始模式和结束模式之间的文本

我正在尝试获取casestartStr和之间的所有内容。我了解如何使用和之间出现的所有事件。我不知道如何将其限制为仅发生的一个实例。endStrbbbstartStrendStrsedbbb

输入示例:

fff
startStr
aaa
bbb
ccc
endStr
xxx
yyy
startStr
ddd
endStr
ddd
bbb

所需输出:

startStr
aaa
bbb
ccc
endStr

这就是我所拥有的:

$ sed -n -e '/startStr/,/endStr/ p' sample.txt
startStr
aaa
bbb
ccc
endStr
startStr
ddd
endStr

答案1

对于第一个startStrendStr,包含/bbb/出现:

 sed -n '/startStr/ {:n; N; /endStr/ {/\n[^\n]*bbb[^\n]*\n/ {p; q}; b}; bn}'

或者

sed -n '/startStr/ {:n; N; /endStr/ {/\nbbb\n/ {p; q}; b}; bn}'

ifbbb不是正则表达式,它正是您需要的字符串(从 begin 到\n)。

解释

对于地址/startStr/,我们:

  • 设置标签:n
  • 阅读下一行N
  • 检查它是否匹配/endStr/
    • 如果这是真的,检查/\nbbb\n/我们读到的这个块中的出现情况;
      • 如果存在,则执行{p; q}“打印并退出”,
      • 否则,执行b“抛出此块并开始搜索下一个”;
  • 如果不是块结束,我们跳转到:n,即继续阅读。

答案2

pcregrep对这份工作的建议是:

pcregrep -M 'startStr(.|\n)*?bbb(.|\n)*?endStr' sample.txt

选项-M允许匹配多行模式,并且*?in 无贪婪运算符。其余的应该是显而易见的。

答案3

修改输入样本以包含之前startStr...endStr没有bbb匹配块的块

$ cat ip.txt 
startStr
foo
bar
endStr
fff
baz
startStr
aaa
bbb
ccc
endStr
xxx
yyy
startStr
ddd
endStr
ddd
bbb


awk解决方案

awk '/startStr/{f=1; m=0; buf = $0; next}
     /bbb/ && f{m=1}
     f{buf = buf ORS $0}
     /endStr/ && f{f=0; if(m==1)print buf}
    ' ip.txt
  • /startStr/{f=1; m=0; buf = $0; next}设置标志来指示块的开始,清除匹配,初始化缓冲区并移至下一行
  • /bbb/ && f{m=1}如果行包含bbb,则设置匹配。f用于避免匹配bbb外部startStr...endStr
  • f{buf = buf ORS $0}只要设置了标志,就累积输入行
  • /endStr/ && f{f=0; if(m==1)print buf}在块末尾,如果找到匹配则打印缓冲区


作为一行:

$ awk '/startStr/{f=1; m=0; buf = $0; next} /bbb/ && f{m=1} f{buf = buf ORS $0} /endStr/ && f{f=0; if(m==1)print buf}' ip.txt 
startStr
aaa
bbb
ccc
endStr


通过吸收整个输入文件的更简单的perl解决方案 - 假设没有类似的块startStr...startStr...endStr(即第一个 startStr 没有 endStr)

$ perl -0777 -ne '(@m) = /startStr.*?endStr\n/gs; print grep { /bbb/ } @m' ip.txt 
startStr
aaa
bbb
ccc
endStr

答案4

sed -n -e '/startStr/,/bbb/p;/bbb/,/endStr/p' /path/to/input

相关内容