我正在尝试从已作为变量读入我的脚本的xml文档中提取值。原始变量 $ data 是:
<item>
<title>15:54:57 - George:</title>
<description>Diane DeConn? You saw Diane DeConn!</description>
</item>
<item>
<title>15:55:17 - Jerry:</title>
<description>Something huh?</description>
</item>
我希望提取第一个标题值,所以
15:54:57 - George:
我一直在使用sed命令:
title=$(sed -n -e 's/.*<title>\(.*\)<\/title>.*/\1/p' <<< $data)
但这只输出第二个标题值:
15:55:17 - Jerry:
有谁知道我做错了什么? 谢谢!
答案 0 :(得分:66)
正如Charles Duffey所述,XML解析器最好使用适当的XML解析工具进行解析。对于一次性工作,以下工作应该有效。
grep -oPm1 "(?<=<title>)[^<]+"
$ echo "$data"
<item>
<title>15:54:57 - George:</title>
<description>Diane DeConn? You saw Diane DeConn!</description>
</item>
<item>
<title>15:55:17 - Jerry:</title>
<description>Something huh?</description>
$ title=$(grep -oPm1 "(?<=<title>)[^<]+" <<< "$data")
$ echo "$title"
15:54:57 - George:
答案 1 :(得分:21)
XMLStarlet或其他XPath引擎是这项工作的正确工具。
例如,data.xml
包含以下内容:
<root>
<item>
<title>15:54:57 - George:</title>
<description>Diane DeConn? You saw Diane DeConn!</description>
</item>
<item>
<title>15:55:17 - Jerry:</title>
<description>Something huh?</description>
</item>
</root>
...您只能使用以下内容提取第一个标题:
xmlstarlet sel -t -m '//title[1]' -v . -n <data.xml
尝试将sed用于此作业是troublesome。例如,如果标题具有属性,则基于正则表达式的方法将不起作用;不会处理CDATA部分;将无法正确识别命名空间映射;无法确定所记录的XML的一部分是否被注释掉;不会忽略属性引用(例如将Brewster & Jobs
更改为Brewster & Jobs
),等等。
答案 2 :(得分:7)
我同意Charles Duffy认为正确的XML解析器是正确的方法。
但是关于你的sed
命令有什么问题(或者你是故意这么做的?)。
$data
未被引用,因此$data
受到shell的单词拆分,文件名扩展以及其他内容的限制。其中一个后果是不保留XML片段中的间距。因此,鉴于您的特定XML结构,此修改后的sed
命令应该可以正常工作
title=$(sed -ne '/title/{s/.*<title>\(.*\)<\/title>.*/\1/p;q;}' <<< "$data")
基本上对于包含title
的行,在标签之间提取文本,然后退出(这样就不会提取第二个<title>
)