【问题标题】:How to print out the last patterns range using awk?如何使用 awk 打印出最后的模式范围?
【发布时间】:2020-05-25 05:20:13
【问题描述】:

我的文件是这样的:

/开始模式/
第一个匹配
/结束模式/

其他文字

/开始模式/
第二场比赛
/结束模式/

其他文字

/begin pattern/
这是我的 想打印出来
/end 图案/
其他文字

如何使用 awk 打印出最后一场比赛?我只知道如何打印出所有这些匹配项。

【问题讨论】:

    标签: awk


    【解决方案1】:

    取决于是否要打印包含分隔符的行:

    $ awk '
        /begin pattern/ { rec=""; f=1 }
        f { rec=rec $0 ORS; if (/end pattern/) {last=rec; f=0} }
        END { printf "%s", last }
    ' file
    /begin pattern/
    This is the one I want to print out
    /end pattern/
    

    或:

    $ awk '
        f { if (/end pattern/) {last=rec; f=0} rec=rec $0 ORS }
        /begin pattern/ { rec=""; f=1 }
        END { printf "%s", last }
    ' file
    This is the one I want to print out
    

    这确保您打印的是一个以begin pattern 开头并以end pattern 结尾的块,因此您不会只打印start pattern 后面的一堆行而没有end pattern(如果最后存在)你的输入文件。如果输入中不存在匹配的块,它还可以确保您不会打印空行。

    【讨论】:

    • 如果您使用awk '/begin pattern/,/end pattern/' 并且在结尾附近有一个开始模式,而在它之后没有结束模式,则将打印该材料。这个问题没有解决发生这种情况时需要什么——它需要第二个示例输入。你记录了你认为“不完整的块”是不应该打印的东西——如果应该打印不完整的块,是否值得记录该怎么做?我认为它变成了END { if (f) last = rec; printf "%s", last },不是吗——至少对于“无分隔符”代码而言。
    • 我从不使用范围表达式,因为它们节省了几个字符而不是使用标志来解决琐碎的问题,然后当问题变得有点有趣时需要完全重写或复制条件,所以在我看来他们是只是从来不值得打扰。如果要打印不完整的块,那么我想你根本没有last 变量,只需打印rec
    • 啊 — 是的,你可能是对的,不使用 last 而只是打印 rec
    【解决方案2】:
    awk 'END { print r } 
    /end pattern/ { f = x }
    /begin pattern/ { f = 1; r = x }
    f++ > 1 { r = r ? r RS $0 : $0 }
    ' infile 
    

    【讨论】:

    • 'x 的使用方式很有趣。在/end pattern/ 中,实际上是0;在/begin pattern/ 中,它实际上是""(空字符串)。它永远不会被设置为任何东西。 IMO,使用0"" 会更清楚。
    • 它当然会起作用,但是在脚本的开头而不是结尾看到 END 语句是很奇怪的。此外,在意识到您使用未设置的变量x 作为空字符串之前,我一直盯着它试图找出rx 之间的区别!不要严重混淆您的代码以节省再输入一个字符 - f 是一个数字,r 是一个字符串,所以而不是 f=xr=x 带有未设置的变量 x,只需使用 @987654337 @ 和 r="" 视情况而定。
    • 现在我明白了代码在做什么——当begin pattern 之后的第一行是0 或为空时,它会失败(跳过它们)。当不存在end pattern 时,它还会打印文件末尾begin pattern 之后的任何行,而不是打印begin patternend pattern 之间的最后一组行,如果输入中不存在匹配块。
    • @EdMorton:这很微妙!如果前面的行包含0(或000.0 或“0 ”等),或者如果它为空(但不是如果该行仅包含一个空白)。解决这个问题需要更多的工程工作。 f++ > 1 条件确保忽略开始模式行。使用ff == 1 将在输出中包含开始模式。要在输出中包含结束模式,您必须在结束模式操作中将 $0 添加到 r
    • @JonathanLeffler 这个“在一个范围内打印文本”的东西是比听起来更复杂的事情之一。我们甚至还没有涉及部分匹配、全行匹配、全字匹配、字符串与正则表达式匹配以及开始和结束字符串可能出现在同一行或中间行的情况。想出一个适用于已发布示例输入集的“解决方案”非常容易,然后在 6 个月后在真实客户数据上运行时崩溃!
    【解决方案3】:

    存储当前匹配并使用 END 块将其打印出来:

    awk '/end pattern/{flag=0} flag{m=$0} /begin pattern/{flag =1}  END{print m}' file
    

    如果 /begin pattern/ 和 /end pattern/ 之间只有一行,则此方法有效。

    【讨论】:

      猜你喜欢
      • 2017-12-23
      • 1970-01-01
      • 2011-05-17
      • 2021-11-26
      • 1970-01-01
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多