【问题标题】:Adding new xml tag using sed in shell script在 shell 脚本中使用 sed 添加新的 xml 标记
【发布时间】:2016-10-08 16:02:02
【问题描述】:

我想使用 shell 变量搜索和添加新的 xml 标签。

使用下面的命令,KVM_IF_LIST_FILE 将存储KVM 实例的所有接口名称[它将包含例如:eno1 eno2 eno3 eno4]。

virsh domiflist $kvm_name|awk {'print $3'}|awk 'NR>2' >> $KVM_IF_LIST_FILE

现在我需要搜索<source dev='eno0/1/2/3' mode='bridge'/>,如果找到上面的模式,需要添加新的xml节点 (<target dev=\'$kvm_name$cnt\'/>) 在上述模式旁边。我编写了下面的 shell 脚本,在这种情况下不起作用。

cnt=0
for i in `cat $KVM_IF_LIST_FILE`
do
echo "Updating macvtap device names for $i"
sed -i.bak "/source dev='\'/a <target dev=\'$kvm_name$cnt\'/>" $XML_FILE
cnt=`expr $cnt + 1`
done

请告诉我如何修改上述脚本以进行上述搜索和替换。

【问题讨论】:

  • 使用 XML 感知工具修改 XML 文档。
  • 如果您在此处搜索 [sed] xml,您会找到 1400 多个答案。你看过他们中的任何一个吗?祝你好运。
  • 使用支持 XML 的工具执行此操作实际上 easy,而使用不支持 XML 的工具执行此操作实际上肯定会遇到一些极端情况,您的代码会创建一个损坏的文档。

标签: xml shell sed


【解决方案1】:

给定以下文件:

<root>
  <prior/>
  <source dev='foo'/>
  <successor/>
</root>

...我们可以在匹配的source 元素之后附加一个新的&lt;target&gt; 元素,如下所示:

kvm_name=hello
cnt=5
xmlstarlet ed \
  --var kvm "'$kvm_name$cnt'" \
  -a '//source' -t elem -n target -v "$kvm_name$cnt" \
  -i '//target' -t attr -n dev -v "$kvm_name$cnt" \
  -d '//target[.=$kvm]/text()' <foo.xml 

...产生以下输出:

<?xml version="1.0"?>
<root>
  <prior/>
  <source dev="foo"/>
  <target dev="hello5"/>
  <successor/>
</root>

【讨论】:

  • 我认为可以而且应该缩短为xmlstarlet ed -a //source -t elem -n target -i //target -t attr -n dev -v "hello5"。无需向节点添加文本,然后删除它。
  • @MichaelVehrs,添加文本的重点是正确识别特定节点。目标不是将属性添加到 every 目标,而只是我们在之前的操作中添加的特定目标。如果已经存在其他目标(例如,hello1hello4),我们就不想编辑它们。
  • 我明白了。但这不能通过更具体的 xpath 表达式来实现吗?
  • @MichaelVehrs,如果我们确定我们使用了正确的编辑原语(-a vs @ 987654332@) 插入该位置。我喜欢这里的成语,因为它是明确的——如果你有一些在数据上下文中是自然标识符的东西,不妨使用它——它不依赖于排序,但实际上,它不是唯一可能的选择.
【解决方案2】:

您可能还没有意识到,但很快就会发现,使用 解析 XML 和 HTML 最终会导致麻烦。例如可以在自身内部重复相同的标签;不能用正则解析。

首先学习一些XSL(好tutorials)来正确转换XML。一个好的开源工具是例如xsltproc

【讨论】:

    最近更新 更多