Awk 查找跨不同线条的图案

Awk 查找跨不同线条的图案,awk,sed,grep,Awk,Sed,Grep,我有这样一个文件(test.txt): 我想搜索“abc\nghi”和“def”所附的78。目前,我知道我可以通过以下方式做到这一点: cat test.txt | awk '/abc/,/def/' | awk '/ghi/,'/def/' 有更好的方法吗?一种方法是使用标志 $ awk '/ghi/ && p~/abc/{f=1} f; /def/{f=0} {p=$0}' test.txt ghi 78 def {p=$0}这将保存输入行以备将来使用 /ghi/&p~

我有这样一个文件(test.txt):

我想搜索“abc\nghi”和“def”所附的78。目前,我知道我可以通过以下方式做到这一点:

cat test.txt | awk '/abc/,/def/' | awk '/ghi/,'/def/'

有更好的方法吗?

一种方法是使用标志

$ awk '/ghi/ && p~/abc/{f=1} f; /def/{f=0} {p=$0}' test.txt
ghi
78
def
  • {p=$0}
    这将保存输入行以备将来使用
  • /ghi/&p~/abc/{f=1}
    如果当前行包含
    ghi
    且前一行包含
    abc
  • f打印输入记录
  • /def/{f=0}
    如果行包含
    def

如果你只想要这两个边界之间的线

$ awk '/ghi/ && p~/abc/{f=1; next} /def/{f=0} f; {p=$0}' ip.txt
78
$ awk '/12/ && p~/abc/{f=1; next} /def/{f=0} f; {p=$0}' ip.txt
34

另请参见awk解决方案:

awk '/ghi/ && r=="abc"{ f=1; n=NR+1 }f && NR==n{ v=$0 }v && NR==n+1{ print v }{ r=$0 }' file
输出:

78

奖金GNU awk方法:

awk -v RS= 'match($0,/\nabc\nghi\n(.+)\ndef/,a){ print a[1] }' file

这并不是很干净,但您可以将记录分隔符重新定义为正则表达式,即
abc\nghi\n | \ndef
。但是,这会创建多个记录,您需要跟踪哪些记录在正确的记录之间。使用awk,您可以使用
RT
检查找到了哪些RS

awk 'BEGIN{RS="abc\nghi\n|\ndef"}
     (RT~/abc/){s=1}
     (s==1)&&(RT~/def/){print $0}
     {s=0}' file
这是:

  • RS
    设置为
    abc\nghi\n
    \ndef
  • 检查是否找到记录,如果
    RT
    包含
    abc
    您找到了第一条记录
  • 如果发现第一个
    RT
    包含
    def
    ,则打印

grep
备选方案

$ grep -Pazo '(?s)(?<=abc\nghi)(.*)(?=def)' file

$grep-Pazo'(?s)(?你可以用sed来做这件事。它并不理想,因为它实际上不理解记录,但它可能适合你

sed -Ene 'H;${x;s/.*\nabc\nghi\n([0-9]+)\ndef\n.*/\1/;p;}' input.txt
基本情况如下:

  • H
    -将当前行附加到sed的“保留空间”
  • ${
    -指定一系列命令的开始,这些命令将在文件结束时运行
  • x
    -将保留空间与模式空间交换,以便将来的替换将使用
    H
  • s/../../
    -分析模式空间(现在是多行),捕获问题中指定的数据,用括号内的表达式替换整个模式空间
  • p
    -打印结果
这里的一个重要因素是正则表达式是ERE,因此
-E
选项很重要。如果您的sed版本使用其他选项来启用对ERE的支持,请改用该选项


另一个需要考虑的问题是,上面的正则表达式采用Unix样式的行尾。如果您试图处理在DOS或Windows上生成的文本文件,正则表达式可能需要稍微不同。

虽然您只想搜索78,但最终的输出应该是什么?嗯……很好……我认为OP尝试的命令给出了预期的输出ut..但可能只需要两行之间的行,因此我编辑了我的回答downvote,没有任何评论,对于可能的答案改进没有太多意义/意义。因此,这种downvote是无意义的,仅适用于grep。在BSD中,
-P
选项不起作用(包括macOS),不过,
pcregrep
通常作为附加包提供。
sed -Ene 'H;${x;s/.*\nabc\nghi\n([0-9]+)\ndef\n.*/\1/;p;}' input.txt