如何用xmlstarlet通过XML注释匹配提取/修改数据?无方案用什么Bash工具?
通过注释匹配提取RRD XML中对应的值
问题场景
我有一份RRD格式的XML文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE rrd SYSTEM "https://oss.oetiker.ch/rrdtool/rrdtool.dtd"> <!-- Round Robin Database Dump --> <rrd> <version>0003</version> <step>10</step> <!-- Seconds --> <lastupdate>1743206258</lastupdate> <!-- 2025-03-28 16:57:38 PDT --> <ds> <name> uptime_remote </name> <type> GAUGE </type> <minimal_heartbeat>600</minimal_heartbeat> <min>2.0000000000e+02</min> <max>2.0000000000e+02</max> <!-- PDP Status --> <last_ds>15508</last_ds> <value>2.0000000000e+02</value> <unknown_sec> 0 </unknown_sec> </ds> <!-- Round Robin Archives --> <rra> <cf>AVERAGE</cf> <pdp_per_row>1</pdp_per_row> <!-- 10 seconds --> <params> <xff>5.0000000000e-01</xff> </params> <cdp_prep> <ds> <primary_value>2.0000000000e+02</primary_value> <secondary_value>2.0000000000e+02</secondary_value> <value>2.0000000000e+02</value> <unknown_datapoints>0</unknown_datapoints> </ds> </cdp_prep> <database> <!-- 2025-03-27 16:57:40 PDT / 1743119860 --> <row><v>2.0000000000e+02</v></row> <!-- 2025-03-27 16:57:50 PDT / 1743119870 --> <row><v>2.0000000000e+02</v></row> <!-- 2025-03-27 16:58:00 PDT / 1743119880 --> <row><v>2.0000000000e+02</v></row> <!-- 2025-03-27 16:58:10 PDT / 1743119890 --> <row><v>2.0000000000e+02</v></row> <!-- 2025-03-27 16:58:20 PDT / 1743119900 --> <row><v>2.0000000000e+02</v></row> <!-- 2025-03-27 16:58:30 PDT / 1743119910 --> <row><v>2.0000000000e+02</v></row> </database> </rra> </rrd>
我正在学习用xmlstarlet操作这个文件,想要提取特定2025-03-27 16:57:40 PDT)。目前用xmlstarlet sel -t --value-of "rrd/rra/database/row/v" test_modified.xml只能导出所有
- 能不能用xmlstarlet实现通过注释匹配并返回对应
值? - 如果不行,有哪些适合Bash脚本的工具可以实现?
解答
1. xmlstarlet实现方案
可以实现。xmlstarlet支持XPath查询,而XPath可以通过comment()函数选中注释节点,结合节点关系定位到对应的
模糊匹配时间戳(适用于只记得部分时间信息的场景)
xmlstarlet sel -t --value-of '//database/comment()[contains(.,"2025-03-27 16:57:40 PDT")]/following-sibling::row[1]/v' test_modified.xml
命令解释:
//database/comment():选中<database>节点下的所有注释节点[contains(.,"目标时间戳")]:过滤出包含目标时间戳的注释/following-sibling::row[1]:选中该注释后面紧邻的第一个<row>节点/v:提取该<row>下的<v>节点值并输出
精确匹配注释内容(避免误匹配)
如果需要确保完全匹配注释内容(去掉前后空白字符),可以用normalize-space()处理:
xmlstarlet sel -t --value-of '//database/comment()[normalize-space(.)="2025-03-27 16:57:40 PDT / 1743119860"]/following-sibling::row[1]/v' test_modified.xml
2. 替代工具方案
如果环境限制无法使用xmlstarlet,以下Bash友好的工具也能实现需求:
awk方案
通过匹配注释行,抓取下一行的<v>值:
awk -v ts="2025-03-27 16:57:40 PDT" ' match($0, "<!--.*" ts ".*-->") { flag=1; next } flag && match($0, /<v>([^<]+)<\/v>/, m) { print m[1]; flag=0 } ' test_modified.xml
sed方案
定位注释行后,提取后续行的<v>内容:
sed -n '/<!--.*2025-03-27 16:57:40 PDT.*-->/ {n;s/.*<v>\([^<]*\)<\/v>.*/\1/p}' test_modified.xml
命令解释:
/<!--.*目标时间戳.*-->/:匹配包含目标时间戳的注释行n:跳转到下一行(对应目标行)
s/.*<v>\([^<]*\)<\/v>.*/\1/p:提取<v>标签内的值并打印
内容的提问来源于stack exchange,提问作者flyingfishfinger
相关产品推荐
相关产品推荐

