bash 替换 XML 文件中的动态内容
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13369933/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Replace dynamic content in XML file
提问by Clucky
Quick Summary:I need to create a Bash script to change the text within a node automatically every week. The script will match the node and replace the text inside them (if this is possible)? How would I do this?
快速总结:我需要创建一个 Bash 脚本来每周自动更改节点内的文本。脚本将匹配节点并替换其中的文本(如果可能)?我该怎么做?
Long Summary:I host a Minecraft server which has shops, each of which have their own .xml file in the /ShowcaseStandalone/ffs-storage/ directory. Every Sunday my server restarts and executes several commands into the terminal to reset several things. One thing that I am trying to make change is one of the shops. I am wanting to change the text in the node <itemstack> and the text in the node <price>. I am simply wanting to take text from a .txt file in a different folder, and insert it into that node. The problem is, that the text in the node will change every week. Is there any way to replace a specific line or text within two nodes using bash?
长摘要:我托管了一个 Minecraft 服务器,里面有商店,每个商店在 /ShowcaseStandalone/ffs-storage/ 目录中都有自己的 .xml 文件。每个星期天我的服务器都会重新启动并在终端中执行几个命令以重置一些东西。我试图改变的一件事是其中一家商店。我想更改节点 <itemstack> 中的文本和节点 <price> 中的文本。我只是想从不同文件夹中的 .txt 文件中获取文本,并将其插入到该节点中。问题是,节点中的文本每周都会更改。有没有办法使用 bash 替换两个节点内的特定行或文本?
XML file:
XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<scs-shop usid="cac8480951254352116d5255e795006252d404d9" version="2" type="storage">
    <enchantments type="string"/>
    <owner type="string">Chadward27</owner>
    <world type="string">Frisnuk</world>
    <itemStack type="string">329:0</itemStack>
    <activity type="string">BUY</activity>
    <price type="double">55.0</price>
    <locX type="double">487.5</locX>
    <locY type="double">179.0</locY>
    <locZ type="double">-1084.5</locZ>
    <amount type="integer">0</amount>
    <maxAmount type="integer">0</maxAmount>
    <isUnlimited type="boolean">true</isUnlimited>
    <nbt-storage usid="23dffac5fb2ea7cfdcf0740159e881026fde4fa4" version="2" type="storage"/>
</scs-shop>
Operating System:Linux Ubuntu 12.04
操作系统:Linux Ubuntu 12.04
采纳答案by Gilles Quenot
You can use xmlstarletto edit a XMLfile in a shelllike this :
您可以使用xmlstarlet这样的方式编辑XML文件shell:
xmlstarlet edit -L -u "/scs-shop/price[@type='double']" -v '99.66' file.xml
NOTE
笔记
- "/scs-shop/price[@type='double']"is a Xpathexpression
- see xmlstarlet ed --help
- "/scs-shop/price[@type='double']"是一个Xpath表达式
- 看 xmlstarlet ed --help
回答by Dan Bliss
The XML way is cool, but if you need to use normal bash tools, you can modify a line using sed. For instance:
XML方式很酷,但是如果您需要使用普通的bash工具,您可以使用sed修改一行。例如:
PRICE=123
sed -i "s/\(<price.*>\)[^<>]*\(<\/price.*\)/$PRICE/" $XML_FILE_TO_MODIFY
This will replace the price with 123.
这将用 123 替换价格。
That sed command seems daunting, so let me break it down:
那个 sed 命令似乎令人生畏,所以让我分解一下:
\(<price.*>\)[^<>]*\(<\/price.*\)is the pattern to match.  \(... \)are parenthesis for grouping.  <price.*>matches the opening price tag. [^<>]*matches anything except angle brackets, and in this case will match the contents of the price tag. <\/price.*matches the end of the price tag.  Forward slash is a delimiter in sed, so I escape it with a back slash.
\(<price.*>\)[^<>]*\(<\/price.*\)是要匹配的模式。  \(...\)是分组的括号。  <price.*>与开盘价标签相符。[^<>]*匹配除尖括号外的任何内容,在这种情况下将匹配价格标签的内容。<\/price.*匹配价格标签的末尾。正斜杠是 sed 中的分隔符,所以我用反斜杠将它转义。
\1$PRICE\2is the text to replace the matched text with.  \1refers to the first matched parenthesis group, which is the opening price tag.  $PRICEis the variable with the desired price in it.  \2refers to the second parenthesis group, in this case the closing tag.
\1$PRICE\2是用来替换匹配文本的文本。  \1指第一个匹配的括号组,即开盘价标签。  $PRICE是包含所需价格的变量。  \2指的是第二个括号组,在这种情况下是结束标记。
回答by Denno
I did not have the luxury of having xmlstarlet. I found a solution though simply by doing an inline replacement;
我没有拥有 xmlstarlet 的奢侈。我通过简单的内联替换找到了一个解决方案;
template-parameter.xml
模板参数.xml
<ns:Parameter>
    <ns:Name required="true">##-ParamName-##</ns:Name>
    <ns:Value>
        <ns:Text>##-ParamValue-##</ns:Text>
    </ns:Value>
</ns:Parameter>
Snippet
片段
tokenName="foo"
tokenValue="bar"    
#Replace placeholders in parameter template element
myParamElement=$(cat template-parameter.xml)
myParamElement=${myParamElement//##-ParamName-##/$tokenName}
myParamElement=${myParamElement//##-ParamValue-##/$tokenValue}  
Result
结果
<ns:Parameter>
    <ns:Name required="true">foo</ns:Name>
    <ns:Value>
        <ns:Text>bar</ns:Text>
    </ns:Value>
</ns:Parameter>

