awk:使用gensub替换段落记录中的多行

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

我有一个输入文件,其中多个段落至少有两个换行符(\n\n),我想从某些段落中的行中提取字段。我认为如果我能让gensub按照我的希望工作,那么处理将是最简单的。考虑以下输入文件:

[Record R1]
    Var1=0
    Var2=20
    Var3=5

[Record R2]
    Var1=10
    Var3=9
    Var4=/var/tmp/
    Var2=12

[Record R3]
    Var1=2
    Var3=5
    Var5=19

我想从记录Var2R1(其中R3实际上并不存在)中仅打印Var2的值。我可以通过设置RS="\n\n"轻松地将所有变量分组到相应的记录中,然后它们都包含在$0中。但是因为我不知道它会在哪里出现在列表中,所以我想使用像gensub这样的东西来提取它。这就是我要做的事情:

awk '
    BEGIN {
        RS="\n\n"
    }
    /Record R1/ || /Record R3/ {
        print gensub(/[\n.]*Var2=(.*)[\n.]*/, "\\1", "g", $0)
    }
' /tmp/input.txt

但它不是仅打印20(来自R1的Var2的值),而是打印以下内容:

[Record R1]
    Var1=0
    20
    Var3=5
[Record R3]
    Var1=2
    Var3=5
    Var5=19

目的是gensub命令中的正则表达式将捕获\n之前和之后的所有字符(换行符:.;以及非换行符:Var2=XX),并用XX替换所有字符。但相反,它只捕获与Var2=XX在同一行上的字符。 awkgensub可以做这种多线替换吗?

我知道另一种方法是循环遍历记录中的所有字段,分割与Var2=符号上的=匹配的字段,但是当我将其扩展到多个变量时感觉效率较低。

regex awk substitution
2个回答
2
投票

我不明白你想用gensub()做什么,但要做你在任何awk中尝试做的事情是:

awk -F'[][[:space:]=]+' '{f[$2]=$3} !NF{if (f["Record"]~/^R[12]$/) print f["Var2"]; delete f}' file
20
12

awk -F'[][[:space:]=]+' '{f[$2]=$3} !NF{if (f["Record"]~/^R[13]$/) print f["Var2"]; delete f}' file
20

gensub()并不关心它所操作的字符串是一行还是多行btw - \n只是一个字符,与其他任何字符都没有区别。

哦,坚持下去,现在我看到你在想那个gensub() - 你的问题是:

  1. [\n.]*的意思是zero or more newlines or periods,但你的输入中没有任何句号,所以它与\n*相同,但你在Var2之前没有任何换行符
  2. Var2在您的第2条记录中不存在,因此正则表达式无法与之匹配。
  3. (.*)将匹配记录结尾的所有内容(最左边的最长匹配)。
  4. "g"具有误导性,因为你只期望1场比赛。

所以在多行文本上使用gensub()不是问题,你的正则表示错误。


0
投票

另一个awk

$ awk -v RS= '/\[Record R[13]\]/{for(i=2;i<=NF;i++)
                                   {v=sub(/ *Var2=/,"",$i);
                                    if(v) print $i}}' file

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