sed多行匹配结合两行之间的删除?

时间:2018-10-01 07:59:39

标签: awk sed multiline

我可以使用sed的多行匹配逻辑来删除一系列行之间的所有行吗?

我一直在尝试各种表达式的组合,但是运气不好。

这是一个示例文件(“ creatures.txt”):

   START TAG
   species: swallowtail butterfly flying
   legs
   wings
   head
   END TAG
   START TAG
   species: common lizard running
   legs
   tail
   head
   END TAG
   START TAG
   species: peacock butterfly resting
   legs
   wings
   head
   END TAG
   START TAG
   species: blackbird flying
   legs
   wings
   head
   END TAG

我想执行以下操作:

  1. 只要我遇到以下多行匹配:(i)第一行中的'START'包含 somewhere ,第二行中的(ii)'butterfly'包含 somewhere
  2. 然后删除“ START TAG”和“ END TAG”行之间的所有行。

因此,使用上面的示例文件,结果将是:

   START TAG
   END TAG
   START TAG
   species: common lizard
   legs
   tail
   head
   END TAG
   START TAG
   END TAG
   START TAG
   species: blackbird
   legs
   wings
   head
   END TAG

谢谢, 詹姆斯。

2 个答案:

答案 0 :(得分:1)

赞:

sed '/START TAG/{N;/butterfly/{:a;/END TAG/!{N;ba};d}}' file

说明:

# Enter block when 'START TAG' is found
/START TAG/ {
    N # Append next line to the pattern buffer
    # Enter block when 'butterfly' is found
    /butterfly/ {
        :a # Create a label (could be also :foo)
        # Enter block unless 'END TAG' is found
        /END TAG/! {
            N # Append next line to pattern buffer
            ba # branch back to label :a
        }
        # Once 'END TAG' is found
        d # Delete the pattern buffer
    }
}

PS:可以使用经过稍微修改的版本来保留START / END标签:

sed '/START/{p;N;/butterfly/{:a;/END/!{N;ba};s/.*\n//}}' file

答案 1 :(得分:1)

每当您发现自己说sed multiline时,都在使用错误的工具。 sed用于在单独的行上执行s / old / new,仅此而已。除此之外,您还应该使用awk。

$ cat tst.awk
{ rec = (rec=="" ? "" : rec ORS) $0 }
/END/ {
    numLines = split(rec,lines,ORS)
    print (lines[2] ~ /butterfly/ ? lines[1] ORS lines[numLines] : rec)
    rec = ""
}

$ awk -f tst.awk file
   START TAG
   END TAG
   START TAG
   species: common lizard running
   legs
   tail
   head
   END TAG
   START TAG
   END TAG
   START TAG
   species: blackbird flying
   legs
   wings
   head
   END TAG

以上内容可以在任何UNIX框上的任何shell中使用任何awk进行工作,如果/稍后您的需求发生变化时可以清晰,简单,强大且易于修改,以查看或打印每条记录或任何组合中的任何其他行每行或整个记录中的值。例如,要生成仅记录该生物具有翅膀的记录的CSV:

$ cat tst.awk
{ rec = (rec=="" ? "" : rec ORS) $0 }
/END/ {
    numLines = split(rec,lines,ORS)
    if ( lines[4] == "wings" ) {
        sub(/species: /,"",lines[2])
        for (i=2; i<numLines; i++) {
            printf "%s%s", lines[i], (i<(numLines-1) ? "," : ORS)
        }
    }
    rec = ""
}

$ awk -f tst.awk file
swallowtail butterfly flying,legs,wings,head
peacock butterfly resting,legs,wings,head
blackbird flying,legs,wings,head

和您可能想要做的其他事情一样琐碎且一致。