【问题标题】:Search for a String and replace string in above line在上面的行中搜索字符串并替换字符串
【发布时间】:2017-04-16 20:32:12
【问题描述】:

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

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

我想查找“许可:无效的许可”并更改其上方的“4”或任何其他数字。

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

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

但它不起作用。有什么建议我可以如何 grep 模式然后更改它上面的值?

【问题讨论】:

  • 请不要使用“巨大”之类的词。使用数字(毕竟我们是工程师)。这很可能会影响答案。

标签: xml bash shell sed xml-parsing


【解决方案1】:

这会有所帮助

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

【讨论】:

    【解决方案2】:

    这里有一个流式 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>
    

    必须在处理之前复制项目元素,因为在处理严重性元素时要“向前看”,而在流模式下无法做到这一点。

    【讨论】:

      【解决方案3】:

      不要将 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
      

      该命令通过将原始值 (4) 替换为 100 来更新 (-u) 元素的值。 XPath 表达式为所有item 元素选择severity 元素,该元素具有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>
      

      【讨论】:

        【解决方案4】:

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

        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
        

        【讨论】:

          猜你喜欢
          • 2020-01-06
          • 2022-08-17
          • 2017-01-10
          • 1970-01-01
          • 1970-01-01
          • 2017-08-05
          • 2010-11-14
          • 1970-01-01
          相关资源
          最近更新 更多