【问题标题】:Awk extract contents between two patterns with least matchesawk 提取两个匹配最少的模式之间的内容
【发布时间】:2016-12-19 05:04:30
【问题描述】:

假设我有一个包含几行的文件:

a1 - first match /a/
b - other stuff
a2 - last match /a/
b
c - first match /c/
c - last match /c/

当我执行awk '/a/,/c/' file时,我会得到

a1 - first match /a/
b - other stuff
a2 - last match /a/
b
c - first match /c/

我想做的是获得/a/和/c/之间的中间部分。但是模式 /a/ 和 /c/ 匹配了几行,并且在这些行之间还有一些其他的东西。所以我想知道是否有一种简单的方法可以得到这样的结果:

a2 - last match /a/
b
c - first match /c/

【问题讨论】:

  • 这里的逻辑是什么?你还有其他例子吗? a 和 c 总是出现两次吗?可以有多块吗?
  • 开始模式和停止模式匹配几行,但我只想要中间部分。假设我们有a\na\na\nb\nc\nc\nc\n,我想得到a\nb\nc\n
  • 管道输出到uniq 以消除重复。
  • 但是如果 "ababcc" 到 "abc" @Barmar
  • 不确定这意味着什么。当我读到这个问题时,看起来你想摆脱ac 的重复。您应该编辑问题以解释您真正想要的内容,而不仅仅是在评论中进行说明。

标签: regex shell awk pattern-matching


【解决方案1】:

你不能用范围表达式来做到这一点。您需要匹配 a 并开始在变量中收集行。如果遇到另一个a,则必须清除变量并重新开始。最后,当您看到 c 时,您会打印该变量。

awk '/^a/ { var = $0; flag = 1; next }
     flag { var = var "\n" $0 }
     /^c/ && flag { print var; flag = 0; var = "" }' file

【讨论】:

  • 我打算将此作为答案发布awk '/^a/{f=1; buf=""} f{buf = buf $0 RS} /^c/{printf "%s",buf; f=0; buf=""}' file,但它与您的几乎相同,所以加 1 给您,而我在评论中的替代语法稍有变化!
【解决方案2】:

由于在读取所有文件之前您无法知道模式最后一次出现的时间,因此最好检查两次:第一次获取匹配项的行号第二个打印其中的行:

awk 'FNR==NR && /^a/ {p1=FNR; next}         # last match of /a/
     FNR==NR && /^c/ && !p2 {p2=FNR; next}  # first match of /c/
     (FNR >= p1) && (FNR <= p2)' file file

使用技巧FNR==NR 区分第一个循环和第二个循环,如Idiomatic awk 中所述。

使用此文件返回:

$ awk 'FNR==NR && /^a/ {p1=FNR; next} FNR==NR && /^c/ && !p2 {p2=FNR; next} (FNR >= p1) && (FNR <= p2)' file file
a2 - last match /a/
b
c - first match /c/

【讨论】:

  • 不应该是&gt;=&lt;=,因为他想在输出中包含ac 行吗?
【解决方案3】:

另一个awk 在数组中累积行数

$ awk '/^a/{delete a; c=0; p=1} 
          p{a[++c]=$0} 
       /^c/{for(k=1;k<=c;k++) print a[k]; exit}' file

a2 - last match /a/
b
c - first match /c/

【讨论】:

    猜你喜欢
    • 2023-01-13
    • 2017-07-01
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    相关资源
    最近更新 更多