Bash 在两个模式之间执行sed,其中结果包含第三个模式

Bash 在两个模式之间执行sed,其中结果包含第三个模式,bash,sed,Bash,Sed,我试图过滤日志文件中的xml响应,使用下面的sed,查找所有xml消息相当容易 sed -n '/<element/,/<\/element/p' file 返回: <element> <id>12345</id> ... </element> <element> <id>54321</id> ... </element> 但是,我无法理解如何应用第二个

我试图过滤日志文件中的xml响应,使用下面的sed,查找所有xml消息相当容易

sed -n '/<element/,/<\/element/p' file
返回:

<element>
    <id>12345</id>
    ...
</element>
<element>
    <id>54321</id>
    ...
</element>
但是,我无法理解如何应用第二个过滤器,这意味着只返回包含特定模式(如ID)的xml响应


在上面的示例中,我如何筛选ID以仅返回第一个?

您可以对范围内的命令进行分组:

sed -n '/<element/,/<\/element/{ /id/p }'

但是,在处理XML时,您应该考虑使用XML工具,例如./P> 为了在搜索特定ID时打印完整条目,需要使用保留空间在节点内累积行数,如果到达节点的结束标记,可以替换保留空间和图案空间,匹配ID并打印:

sed -n -e '
  /<element/,/<\/element/H # append to the hold space
  /<\/element/{ 
    g  # replace pattern space with hold space
    /<id>12345<\/id>/p  # print if matching ID
    s/.*//  # clear pattern space
    x  # clear hold space
    b  # start next cycle without further output
}' input-file

你看,这很快就会变得一团糟。

sed是用来做s/old/new/的,仅此而已。它所有古怪的单字符符文语言结构在20世纪80年代中期awk发明时就已经过时了

$ cat tst.awk
/<element>/ { inElt = 1 }
inElt {
    elt = (elt == "" ? "" : elt ORS) $0
    if ( /<\/element>/ ) {
        if ( elt ~ /<id>12345<\/id>/ ) {
            print elt
        }
        elt = ""
        inElt = 0
    }
    next
}
{ print }

$ awk -f tst.awk file
<element>
    <id>12345</id>
    ...
</element>
与目前接受的sed解决方案相比,上述解决方案的主要优点是:


它不需要您对进行两次测试,这可能适用于GNU-sed:

sed -n '/<element>/{:a;/<\/element>/!{N;ba};/<id>12345<\/id>/p}' file
这将使用保存在保留空间中的计数器,该计数器在每个完整集合上递增,并检查特定数字


注意:range运算符可以用作触发器类型的命令,但通常是开始地址{:a;N;end address!ba;commands on collection}更有用。

请在您的帖子中添加输入样本和输出样本。需要哪些样本?您的问题输入和输出样本,以便我们更好地理解您的问题。如果确实需要,那么好吧。这个解决方案不起作用,产生的输出相当于根据原始查询输出的id使用grep。@Andrew我意识到你想在我写答案后不久打印出整个条目。看看第二个sed脚本,它做了你想要的,我想。我理解它很混乱,但当你被告知必须以Y的方式做X时,就会发生这种情况。这些文件位于服务器上,处理起来相当麻烦,因此,我们必须这样做,而不是更改内容,以便以更好的方式记录xml消息:|唯一与此解决方案不符的是搜索id的硬编码。将elt~/12345/替换为elt~idQuery,并将执行更改为awk-v idQuery=id>12345@Andrew我无法从问题中判断是否需要特定的id值,或者第一个元素包含任何id标记,或者只是第一个元素,不管它的内容是什么,所以我只是复制了接受的sed脚本所做的操作,以便您可以看到比较。
sed -n '/<element>/{:a;/<\/element>/!{N;ba};/<id>12345<\/id>/p}' file
sed -n '/<element>/{:a;/<\/element>/!{N;ba};x;s/^/x/;/^x\{2\}$/{x;p;b};x}' file