【问题标题】:Print all lines between two patterns (which may not be pairs) with AWK/SED/GREP使用 AWK/SED/GREP 打印两个模式(可能不是对)之间的所有行
【发布时间】:2020-10-26 20:06:04
【问题描述】:

我知道这个问题有多个实例,例如Print all lines between two patterns, exclusive, first instance only (in sed, AWK or Perl) 但我的问题是这两种模式是否可能无法配对 - 例如

给定输入

PATTERN1
bbb
ccc
ddd
eee
fff
PATTERN1
ggg
hhh
iii
PATTERN2
jjj
PATTERN2
kkk

我希望输出最短范围:

ggg
hhh
iii

这可能吗?

【问题讨论】:

    标签: bash awk sed grep


    【解决方案1】:

    您能否尝试仅在 GNU awk 中根据您显示的示例进行跟踪、编写和测试。

    awk '
    /PATTERN1/ && found1 && !found2{
      found1=found2=val=""
    }
    /PATTERN1/{
      found1=1
      next
    }
    /PATTERN2/{
      found2=1
      if(found1){
        print val
      }
      found1=found2=val=""
      next
    }
    {
      val=(val?val ORS:"")$0
    }
    ' Input_file
    

    给定样本的输出将是:

    ggg
    hhh
    iii
    

    说明:为上述添加详细说明。

    awk '                              ##Starting awk program from here.
    /PATTERN1/ && found1 && !found2{   ##Checking if PATTERN1 in current line and found1 is SET and found2 is NOT SET then do following.
      found1=found2=val=""             ##Nullifying found1, found2 and val variables here.
    }
    /PATTERN1/{                        ##Checking condition if PATTERN1 is found then do following.
      found1=1                         ##Setting found1 here for flagging.
      next                             ##next will skip all further statements from here.
    }
    /PATTERN2/{                        ##Checking condition if PATTERN2 is found then do following.
      found2=1                         ##Setting found2 here for flagging.
      if(found1){                      ##Checking condition if found1 is SET then do following.
        print val                      ##Printing val here.
      }
      found1=found2=val=""             ##Nullifying found1, found2 and val here.
      next                             ##next will skip all further statements from here.
    }
    {
      val=(val?val ORS:"")$0           ##Creating val which has current line value and keep appending it with new line.
    }
    ' Input_file                       ##Mentioning Input_file name here.
    

    【讨论】:

    • 我花了一分钟才用PATTERN1[2] 捕捉到你,这就是你在没有数组:) 的情况下如何做到的
    • @DavidC.Rankin,是的,为展示的样本工作,我希望这能帮助 OP 欢呼:)
    • 是的,这就像一个冠军。我只是不确定 OP 与列出的确切模式的关联程度。没有理由不这样做。
    • 谢谢! @DavidC.Rankin 效果很好!抱歉回复晚了:p 我也发现了一个 hack:awk 'f{{x=x"\n"$0}} {from_pattern}/{{x=$0; f=1}} f && /{to_pattern}/ {{print x; f=0}}' {path_to_file}
    【解决方案2】:

    awk 中,您可以保存PATTERN.. 并在每次遇到PATTERN.. 时进行比较。在两者之间,您将元素保存在一个数组中,当您有两个不匹配的模式时 - 您输出数组的内容。否则你清空数组并重置你的计数器,例如

    awk '! /PATTERN/ {
            a[++n]=$0
        }
        /PATTERN/ {
            if ($0 != lastptrn)
                for (i=1; i<=n; i++)
                    print a[i]
            delete a
            n=0
            lastptrn=$0
        }
    ' file
    

    输出

    ggg
    hhh
    iii
    

    【讨论】:

      【解决方案3】:

      如果Perl恰好是您的选择,请尝试一下:

      perl -0777 -ne '/.*PATTERN1\n(.*?)PATTERN2/s && print $1' input
      

      结果:

      ggg
      hhh
      iii
      
      • -0777 选项告诉 Perl 一次吞掉所有行。
      • 正则表达式的s 选项告诉Perl 在元字符. 中包含换行符。
      • .*PATTERN1\n 将位置缠绕到最后一个 PATTERN1 结束。
      • (.*?) 指定最短匹配并将$1 分配给匹配的行。

      【讨论】:

      • Perl 是解决此类问题的正确工具.. 顶一下!..
      【解决方案4】:

      另一个:

      $ awk '
      /PATTERN1/ {                # at starting pattern
          f=1                     # flag up
          b=""                    # reset buffer
          next                    # to exclude the start pattern
      }
      /PATTERN2/ {                # at ending pattern
          print b                 # output buffer
          exit                    # no need to continue to the end
      }
      f {                         # when flag up
          b=b (b==""?"":ORS) $0   # buffer records
      }' file
      

      要包括开始和结束标记,请删除next 并将f {...} 移到/PATTERN2/ {...} 之前

      【讨论】:

        【解决方案5】:

        这可能对你有用(GNU sed):

        sed -n '/PATTERN2/{g;/PATTERN1/{s/[^\n]*\n//p;q}};H;/PATTERN1/h' file
        

        概述:将行从PATTERN1 复制到但不包括PATTERN2 到保留空间,然后打印保留空间减去第一行。

        处理:将所有行追加到保持空间,当匹配时用PATTERN1的内容替换保持空间。

        PATTERN2匹配时,用保持空间覆盖模式空间,如果模式空间包含PATTERN1,删除第一行,打印模式空间的内容并退出。

        【讨论】:

          最近更新 更多