我请求你的帮助。
我查阅了很多资料,并使用 awk 和 sed 做了一些测试,但我无法让它工作。下面是配置文件的片段,我可以通过 grep 获得输出,但不是我需要的方式。
> file.txt
>
> "<property>name="DBName"><value>ABC</value>name="DBName"><value>DEF</value></property>
>
> cat file.xml | grep -o -P '.name="DBName"><value>.{0,20}'
> name="DBName"><value>ABC</value>
> name="DBName"><value>DEF</value></propert
期望的输出是:
ABC
DEF
谢谢你的帮助。
和我
答案1
如果(巨大的,巨大的“如果”)你的文件实际上只有非常简单的情况,你想要精确的string<value>
后跟一些非<
字符,然后是,因此您的问题可以表述为“获取在每次出现及其后的第一个</value>
出现之间找到的简单的非换行符字符串”,然后您可以执行以下操作(使用 GNU ) :<value>
<
grep
grep -oP '<value>\K[^<]+' file
当然,即使稍有不同,这也会失败。例如,如果您有多行值,或者值标记可以具有类似<value foo=bar>
或 的内容,则可以在任意数量的其他完全有效的 XML 情况下进行。正确的方法©是使用 XM: 解析器。您可能想查看xmllint
或者XML小星除其他外。
答案2
如果您的所有输入看起来与您发布的一行示例输入完全相同:
$ cat file
"<property>name="DBName"><value>ABC</value>name="DBName"><value>DEF</value></property>
然后使用任何 awk:
$ awk -F'[<>]+' '{for (i=5; i<=NF; i+=4) print $i}' file
ABC
DEF
但是,与任何其他不使用 XML 解析器的解决方案一样,它很脆弱。
答案3
使用XMLStarlet
:
XML 文件取自答案。
<config>
<property name="DBName"><value>ABC</value></property>
<property name="DBName" year="2023"><value>DEF</value></property>
<property name="SystemName"><value>s70</value></property>
</config>
$ xmlstarlet select -t -v '//value' --nl ex.xml
ABC
DEF
s70
$ xmlstarlet select -t -m '//property[@name="DBName"]' -v 'value' --nl ex.xml
ABC
DEF
使用 awk:
$ awk -v pat1="<value>" -v pat2="</value>" '
{
while (match($0, pat1)){
$0=substr($0,RSTART+RLENGTH);
if (match($0, pat2)) print substr($0,1,RSTART-1)
}
}
'
和解决awk
方案pcregrep
适用于该问题,但在很多情况下可能会失败。
$ pcregrep -o1 '<value>(.*?)</value>'
答案4
如果您有一个格式良好的 XML 输入,例如我们
<config>
<property name="DBName"><value>ABC</value></property>
<property name="DBName" year="2023"><value>DEF</value></property>
<property name="SystemName"><value>s70</value></property>
</config>
您可以使用 XML 感知工具,并使用 Xpath(或类似工具)来选择要提取的部分。示例为希德尔:
## 1) get all values:
$ xidel -e "//value" ex.xml
ABC
DEF
s70
## 2) get the values inside "property" with attribute "name" "DBname"
$ xidel -e "//property[@name='DBname']/value" ex.xml
ABC
DEF