在上面的行中搜索String并替换字符串

时间:2016-12-02 02:02:35

标签: xml bash shell sed xml-parsing

我有一个巨大的XML文件,需要更改我知道的一行以上的几百行。

<errorCode>4544</errorCode>
<severity>4</severity>
<modelDescription>Licensing: Invalid license</modelDescription> 

我想要&#34;许可:无效的许可证&#34;并改变&#34; 4&#34;高于它或任何其他数字。

我正在尝试做类似的事情:

sed -i '/Invalid license/{n;s/4/6/;}' file

但它不起作用。任何建议我如何grep一个模式,然后更改它上面的值?

4 个答案:

答案 0 :(得分:0)

您可以存储上一行并检查当前行是否与您的模式匹配。如果是这样,请修改上一行并打印,否则打印。请参阅以下内容:

while IFS= read line
do
    echo $line | grep "<severity>[0-9]</severity>" > /dev/null && { 
        sev=$line
    } || {
        echo $line | grep "Invalid license" > /dev/null && {
            echo $sev | sed "s/4/5/"
        } || {
            if [ ! -z $sev ]; then echo $sev; fi
        }
        sev=""
        echo $line
    }
done < file

答案 1 :(得分:0)

不要将SED用于XML解析,因为它不是为处理XML语法而设计的,而在SED中编写XML解析器是一项艰巨的任务。此外,有许多有用的工具正是为了这个目的。

考虑这个XML:

<root>
  <item>
    <errorCode>4000</errorCode>
    <severity>2</severity>
    <modelDescription>Some error</modelDescription>
  </item>
  <item>
    <errorCode>4544</errorCode>
    <severity>4</severity>
    <modelDescription>Licensing: Invalid license</modelDescription>
  </item>
</root>

您可以使用xmlstarlet轻松修改severity值:

xmlstarlet ed -u '//item[severity = 4
and modelDescription = "Licensing: Invalid license"]/severity' \
  -v 100 file.xml

该命令通过将原始值(-u)替换为severity来更新4元素100元素的值。 XPath表达式选择severity个元素的item个元素,其中severity子元素值为4modelDescription子元素值为Licensing: Invalid license

结果打印到标准输出。要就地编辑文件,请使用--inplace选项:xmlstarlet ed --inplace -u ...

输出

<?xml version="1.0"?>
<root>
  <item>
    <errorCode>4000</errorCode>
    <severity>2</severity>
    <modelDescription>Some error</modelDescription>
  </item>
  <item>
    <errorCode>4544</errorCode>
    <severity>100</severity>
    <modelDescription>Licensing: Invalid license</modelDescription>
  </item>
</root>

答案 2 :(得分:0)

这是一个流式XSLT 3.0转换,可以完成这项工作,假设您显示的元素包含在item元素中:

<xsl:transform version="3.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:mode streamable="yes" on-no-match="shallow-copy"/>
<xsl:mode name="c" streamable="no" on-no-match="shallow-copy"/>

<xsl:template match="item">
  <xsl:apply-templates select="copy-of(.)" mode="c"/>
</xsl:template>

<xsl:template mode="c"
  match="severity[following-sibling::modelDescription=
                    'Licensing: Invalid license']">
  <severity>6</severity>
</xsl:template>

</xsl:transform>

必须在处理之前复制item元素,因为您希望在处理severity元素时“向前看”,而在流模式下无法完成。

答案 3 :(得分:0)

这可能会帮助

sed -i.bak '/Invalid license/!{x;1!p;d;};x;s/4/6' <file path>