关于 awk 匹配一系列行之间的模式的说明

问题描述 投票:0回答:1

所以我有一个 awk 一句话,虽然我理解 什么正在高水平上完成,但我不完全理解 awk 是如何完成我给它的任务的。我要求 awk 仅在满足特定模式时才给我一系列文本。

这是我的 file.txt 的内容:

START
        Name: Apple
        Kingdom: Plantae
        Family: Rosaceae
END
--------------------
START
        Name: Cat
        Kingdom: Animalia
        Family: Felidae
END
--------------------
START
        Name: Orange
        Kingdom: Plantae
        Family: Rutaceae
END
--------------------
START
        Name: Dog
        Kingdom: Animalia
        Family: Canidae
END
--------------------

这是我传递的一行命令:

awk '/START/ {var=""} {var=var ? var ORS $0 : $0} /END/ {if(var~/Plantae/) print var}' file.txt

如果满足条件

var~/Plantae/
,则根据需要返回范围:

07-09-24 13:56:28 terucin @ mean_machine:/home/terucin/Research/Sanity [-130] $ awk '/START/ {var=""} {var=var ? var ORS $0 : $0} /END/ {if(var~/Plantae/) print var}' file.txt
START
        Name: Apple
        Kingdom: Plantae
        Family: Rosaceae
END
START
        Name: Orange
        Kingdom: Plantae
        Family: Rutaceae
END
07-09-24 13:56:33 terucin @ mean_machine:/home/terucin/Research/Sanity [+0] $

所以我知道一些事情:

  • /START/
    = 我的范围的起始标志
  • /END/
    = 我的范围的结束标志
  • {var=""}
    = 将 var 设置为空字符串
  • condition ? Yay : Boo
    = 如果条件为 true,则使用 true 表达式:“Yay”,否则使用 false 表达式:“Boo”

我想我知道这里的基础知识:

  • 我使用
    START
    作为我的起始标志(标志打开)和
    END
    作为我的结束标志(标志关闭)来设置我想要搜索的行的“范围”
  • 如果我的范围内的任何记录包含模式
    Plantae
    awk 返回标志之间的所有行,包括标志。
  • 排除此标志范围之外的任何内容,以及不包含所需模式的任何范围

非常简洁,并且符合我通过 CLI 使用 awk 而不是更强大和更高级的编程语言或方法的场景(诚然相当小众)。

我不知道如何实现这一点。看起来,如果

var
等于
var
(在这种情况下总是成立?也许?),则使用表达式
var ORS $0
。但我的理解如下:

    此时
  • var
    等于空
  • ORS
    将默认为换行符
  • $0
    是正在读入的当前记录(即行),并且是迄今为止唯一被“设置”的值,除了
    var
    被设置为空

所以,显然,幕后还有其他恶作剧正在进行,但我并不能 100% 知道这些恶作剧到底是什么。

我在最后的

print
部分尝试了一些东西,只是为了看看最后设置了什么,我的结论大致是:

  • 如果我打印
    ORS
    而不是
    var
    ,我只会得到等于带有我的标志的记录数的换行符。因此,如果我使用第一个示例
    var~/Plantae/
    ,我会得到四个换行符(两个
    START
    和两个
    END
    行,因为
    Apple
    Orange
    都在其范围内包含模式
    Plantae
    ),但如果我只匹配
    var~/Apple/
    我只得到两个换行符(一个
    START
    和一个
    END
    行,因为只有一个范围包含
    Apple
  • 如果我打印
    $0
    ,我会得到
    END
    ,这是或者标志关闭,或者可能是正在读取的最终记录,我不确定。这两个选项在功能上可能是相同的(无论如何都在这里打印
    END
    ),但也许在标记关闭和正在读取的最终记录之间存在重要的语义差异需要注意?这也返回
    END
    等于与
    if() print
    语句匹配的“范围”的数量,如我之前的要点所述(因此
    /Apple/
    仅返回
    END
    一次,而
    /Plantae/
    返回
    END
    两次)

我的问题归结为如何在 awk 中设置所有这些?

var
如何最终包含包括标志在内的整个范围,但
ORS
似乎只保留换行符,而
$0
只是最终标志/最后一条记录(同样,不确定这是哪个)?

linux awk range pattern-matching
1个回答
0
投票

如果

var
等于
var
(在这种情况下始终为真?也许?),则使用表达式
var ORS $0

你误读了。

=
是赋值,不是比较。所以
var =
正在分配给
var
,它不是将
var
与任何东西进行比较。

它正在对三元表达式的结果进行赋值

var ? var ORS $0 : $0

这意味着如果

var
不为空,则使用
var ORS $0
,否则使用
$0
。这会生成一个以空格分隔的行列表,并且条件防止在列表中的第一项之前放置空格。

© www.soinside.com 2019 - 2024. All rights reserved.