【问题标题】:sed command to replace second occurrence of xml tagsed 命令替换第二次出现的 xml 标记
【发布时间】:2016-04-02 03:21:29
【问题描述】:

我有一个示例 config.xml 文件,如下所示:

<maven2-moduleset>
  <actions/>
   <jdk>JDK 6 Update 26</jdk>
  <publishers>
    <hudson.plugins.sonar.SonarPublisher plugin="sonar@2.1">
      <jdk>jdk1.8</jdk>
    </hudson.plugins.sonar.SonarPublisher>
  </publishers>
</maven2-moduleset>

我想更改第二次出现的&lt;jdk&gt;&lt;/jdk&gt; 标记。于是我用sed命令来做,如下图:

sed -i "s/<jdk>\.*<\/jdk>/<jdk>jdk1.7.0_76<\/jdk>/2" config.xml

但是那个文件没有变化。我哪里错了?

注意:第二次出现的 jdk 标签可以包含任何 jdk 版本。我想将该标签中提到的任何值(版本)替换为此值 =“jdk1.7.0_76”。 和, 我不能使用 perl 或 xmlstarlet。

【问题讨论】:

    标签: regex xml bash sed


    【解决方案1】:

    您的模式将匹配标签之间任意数量的文字.,仅此而已,这不是您想要的。此外,您附加一个 2 是因为您想匹配第二次出现的 jdk 标记对,但这只有在您的两对 jdk 标记出现在同一行时才有效。

    如果您想匹配在 jdk 标记之间某处包含单个句点的任何内容,那么这将起作用:

    sed -i "s#<jdk>.*\..*</jdk>#<jdk>jdk1.7.0_76</jdk>#" config.xml
    

    这只会替换第二个 jdk 标签对,因为第一个标签不包含在上面的正则表达式中与 \. 匹配的 .

    你也可以匹配任何不包含空格的东西:

    sed -i "s#<jdk>[^ ]*</jdk>#<jdk>jdk1.7.0_76</jdk>#" config.xml
    

    这很有效,因为您的示例中只有第二个实例缺少空格。

    最后你可以告诉 sed 只替换出现在hudson 标签之间的jdk 标签:

    sed -i "/<hudson/,/<\/hudson/ s#<jdk>.*</jdk>#<jdk>jdk1.7.0_76</jdk>#" config.xml
    

    我使用# 而不是/ 作为搜索分隔符,因为与/ 不同,它不会出现在正则表达式中。

    【讨论】:

    • 另外一个用于建议如何编写严格的规则。 (例如 jdk[0-9.]* 代替 .*)和“仅在 hudson 之间匹配”是一个不错的选择。
    • @julian 解释得很好。谢谢。它就像一个魅力。
    【解决方案2】:

    对于这种特定情况,您可以使用以下 sed 命令:

    sed -i "s/<jdk>jdk.*<\/jdk>/<jdk>jdk1.7.0_76<\/jdk>/g" config.xml
    

    这应该用您自己的 jdk 版本替换 jdk xml 标记中的任何 jdk[version] 字符串。

    但是,我建议您使用awk 来执行此操作。 这应该可以解决问题:

    awk '/<jdk>.*<\/jdk>/{c+=1}{if(c==2){sub("<jdk>.*</jdk>","<jdk>jdk.1.7.0_76</jdk>",$0)};print}' config.xml > config_new.xml
    

    它会寻找第二次出现&lt;jdk&gt;&lt;/jdk&gt; xml 标记,然后替换版本。

    【讨论】:

    • 我知道您更专注于解决 awk 的问题,但是由于输入中的前导空格以及您在解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 2015-10-07
    • 2020-12-09
    • 1970-01-01
    • 2014-10-28
    • 1970-01-01
    相关资源
    最近更新 更多