我正在尝试为xml响应过滤日志文件,并使用sed如下所示,查找所有xml消息相当容易。
sed -n '/<element/,/<\/element/p' file
返回:
<element>
<id>12345</id>
...
</element>
<element>
<id>54321</id>
...
</element>
但是,我一直无法弄清楚如何应用第二个过滤器,这意味着仅返回包含特定模式(例如ID)的xml响应。
在上面的示例中,如何过滤ID以仅返回第一个?
答案 0 :(得分:2)
您可以将范围的命令分组:
sed -n '/<element/,/<\/element/{ /id/p }'
但是,在处理XML时,您应该真正考虑使用XML工具,例如xmlstarlet。
要在搜索特定ID时打印完整的条目,如果到达了的结束标记,则需要使用保持空间在<element>
节点内累积行。一个<element>
节点,您可以替换 hold 和模式空格,匹配您的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
你看,这真的很快变得很混乱。
答案 1 :(得分:2)
sed用于做s / old / new / 一无所有。在1980年代中期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解决方案相比,上述方法的主要优点是:
</element
测试两次例如,假设您要打印文件中的第一个元素,而不管其ID是什么,而不是包含特定ID的元素。这将是上面的琐碎调整:
$ cat tst.awk
/<element>/ { inElt = 1 }
inElt {
elt = (elt == "" ? "" : elt ORS) $0
if ( /<\/element>/ ) {
if ( ++cnt == 1 ) {
print elt
}
elt = ""
inElt = 0
}
next
}
{ print }
$ awk -f tst.awk file
<element>
<id>12345</id>
...
</element>
如果要打印27号而不是1号元素,只需将++cnt == 1
更改为++cnt == 27
。尝试修改sed脚本以进行如此琐碎的需求更改,您可以期待完全的重写,并且必须调用其他工具。是否要打印多个元素和/或文件的其他部分不在元素标签内?与awk也绝对无关紧要。希望你明白了。
答案 2 :(得分:0)
这可能对您有用(GNU sed):
sed -n '/<element>/{:a;/<\/element>/!{N;ba};/<id>12345<\/id>/p}' file
通过使用-n
选项来使用类似seds grep的性质,该选项可以关闭每行的自动打印。遇到包含<element>
的行时,收集一系列行,直到到达结束标记</element>
。现在检查<id>12345</id>
的集合,如果为true,则打印该集合,否则该集合将被传递。
如果相反,您想要特定的元素,例如第二,使用:
sed -n '/<element>/{:a;/<\/element>/!{N;ba};x;s/^/x/;/^x\{2\}$/{x;p;b};x}' file
这将使用保存在保存空间中的计数器,该计数器在每个完整集合中都会递增,并检查一个特定的数字。
范围运算符,
可以用作触发器类型的命令,但通常start address{:a;N;end address!ba; commands on collection}
更为有用。