【问题标题】:Awk between two patterns with pattern in the middle两个模式之间的 awk,中间有模式
【发布时间】:2013-08-21 14:21:38
【问题描述】:

您好,我正在寻找一个 awk,它可以找到两种模式并将它们之间的数据打印到 仅当中间有第三种模式时才创建文件。 例如:

Start
1
2
middle
3
End
Start
1
2
End

And the output will be:
Start
1
2
middle
3
End

我在网上找到了 awk '/patterns1/, /patterns2/' path > text.txt 但我只需要在中间输出第三个模式。

【问题讨论】:

  • 繁琐但可行。你需要在Start和End之间保存素材,遇到Middle的时候注意要打印保存的素材,在处理End的时候看是否打印保存的素材。我现在没有时间将其简化为代码。 (识别开始后将每个$0 保存在一个数组中;在结束时停止保存,如果合适则打印数组并无论如何清除数组。)
  • 另外,Start 和 End 之间是否有任何数据行?还是它总是一系列 Start..End 行,但只需要打印其中的一些。
  • 可以为空,但我只需要中间图案的那个
  • 所以该文件可能包含:Start1middle2EndJunk<blank line>Start、@987654331 4, End? Junk<blank line> 不应该包含在输出中吗?只有前 5 行应该回显?
  • 垃圾行或空行可能在中间提供的开头和结尾内

标签: linux shell unix awk sh


【解决方案1】:

这是一个没有标志的解决方案:

$ awk 'BEGIN{RS="End"}/middle/{printf "%s", $0; print RT}'  file
Start
1
2
middle
3
End

说明:RS变量是记录分隔符,所以我们将其设置为“End”,这样每条Record都用“End”分隔。

然后我们使用/middle/过滤器过滤包含“中间”的记录,对于匹配的记录,我们用$0打印当前记录,用print RT打印分隔符

【讨论】:

  • 有趣...但我认为它需要对其工作原理进行一些解释。
  • 这不考虑Start,它只打印包含middleEnd的记录。您还在记录后添加了一个额外的换行符。
  • @JonathanLeffler 添加了解释
  • 在问题级 cmets 中查看我对 OP 的辅助问题。如果除了 Start..End 序列之外没有任何东西,这会很好地工作;如果还有其他数据需要删除,就不会那么热了。不过,如果数据允许它工作,这是个好主意。
【解决方案2】:

这个 awk 应该可以工作:

awk '$1=="Start"{ok++} ok>0{a[b++]=$0} $1=="middle"{ok++} $1=="End"{if(ok>1) for(i=0; i<length(a); i++) print a[i]; ok=0;b=0;delete a}' file

Start
1
2
middle
3
End

扩展:

awk '$1 == "Start" {
   ok++
}
ok > 0 {
   a[b++] = $0
}
$1 == "middle" {
   ok++
}
$1 == "End" {
   if (ok > 1)
      for (i=0; i<length(a); i++)
         print a[i];
   ok=0;
   b=0;
   delete a
}' file

【讨论】:

    【解决方案3】:

    只需在awk 中使用一些标志:

    /Start/ {
        start_flag=1
    }
    
    /middle/ {
        mid_flag=1
    }
    
    start_flag {
        n=NR;
        lines[NR]=$0
    }
    
    /End/ {
        if (start_flag && mid_flag)
            for(i=n;i<NR;i++)
                print lines[i]
        start_flag=mid_flag=0
        delete lines
    }
    

    【讨论】:

      【解决方案4】:

      修改了awk用户000001

      awk '/middle/{printf "%s%s\n",$0,RT}' RS="End" file
      

      编辑: 添加了开始标签的测试

      awk '/Start/ && /middle/{printf "%s%s\n",$0,RT}' RS="End" file
      

      【讨论】:

      • 这不检查Start
      • 更新了我的帖子以测试Start
      【解决方案5】:

      这适用于任何现代 awk:

      awk '/Start/{f=1;rec=""} f{rec=rec $0 ORS} /End/{if (rec~/middle/) printf "%s",rec}' file
      

      将 RS 设置为“End”的解决方案是特定于 gawk 的,这可能很好,但绝对值得一提。

      【讨论】:

        猜你喜欢
        • 2023-01-13
        • 2014-09-07
        • 1970-01-01
        • 2020-03-02
        • 2019-09-28
        • 2012-02-10
        • 2016-01-04
        • 2021-01-22
        • 1970-01-01
        相关资源
        最近更新 更多