【问题标题】:Is it possible to use sed to replace dependencies's version in a pom file?是否可以使用 sed 替换 pom 文件中依赖项的版本?
【发布时间】:2016-01-22 23:24:44
【问题描述】:

我有一个pom.xml 文件,我想将任何dependency 节点中的版本从0.1-SNAPSHOT 替换为不同的版本(比如说NEW-VERSION),我唯一的限制是替换只有当groupId 匹配特定文本时才应该这样做,比如说:com.company.xyz

话虽如此,假设这是我的pom.xmldependencies 部分:

<dependencies>
        <dependency>
            <groupId>com.company.xyz</groupId>
            <artifactId>xyz-xx-utils</artifactId>
            <version>0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.ibm.xyz</groupId>
            <artifactId>xyz</artifactId>
            <version>56.1</version>
        </dependency>
</dependencies>

应用 sed 命令后,我希望它看起来像:

<dependencies>
        <dependency>
            <groupId>com.company.xyz</groupId>
            <artifactId>xyz-xx-utils</artifactId>
            <version>NEW-VERSION</version>
        </dependency>

        <dependency>
            <groupId>com.ibm.xyz</groupId>
            <artifactId>xyz</artifactId>
            <version>56.1</version>
        </dependency>
</dependencies>

这是我尝试过但没有成功的方法:

newVersion="NEW-VERSION"

sed -i "s/\(<dependency>\)\(<groupId>com.company.xyz</groupId>\)\(<artifactId>.*\</artifactId>\)\(<version>0.1-SNAPSHOT</version>\)\(</dependency>\)/\1\2\3$newVersion\5/" pom.xml

我想知道这不起作用的原因是否是因为我的文本有多行,所以我研究了一下,但我不明白用于处理多行的语法(一些N 的东西)。

顺便说一句,我将这段代码包含在执行其他操作的 bash 文件中,这就是为什么我想使用 sed 或任何其他与 bash 兼容的“工具”来执行此操作。

【问题讨论】:

  • 请注意,使用 maven 属性可能会使这在未来变得更容易。例如&lt;version&gt;NEW-VERSION&lt;/version&gt; 变成 &lt;version&gt;NEW-${xyz-xx-utils.version}&lt;/version&gt; 然后你在别处定义它,例如&lt;xyz-xx-utils.version&gt;1.2-SNAPSHOT&lt;/xyz-xx-utils.version&gt;
  • 你为什么不用版本插件?

标签: regex bash maven sed


【解决方案1】:

我建议使用 maven 属性,这些属性通过 sed 搜索和替换清晰且意外容易处理。

所以 pom.xml 看起来像:

<properties>
    <xyz-xx-utils.version>2.0</xyz-xx-utils.version>
</properties>
<dependencies>
    <dependency>
        <groupId>com.company.xyz</groupId>
        <artifactId>xyz-xx-utils</artifactId>
        <version>${xyz-xx-utils.version}</version>
    </dependency>
</dependencies>

更改版本的命令行将是:

sed -i.bak  "s/<xyz-xx-utils.version>.*<\/xyz-xx-utils.version>/<xyz-xx-utils.version>NEW-VERSION<\/xyz-xx-utils.version>/g"  $pomfile

【讨论】:

    【解决方案2】:

    带有自定义RS(记录分隔符)的gnu-awk 更适合这个:

    awk -v RS="</dependency>" 'index($0, "<groupId>com.company.xyz</groupId>"){
        sub(/0\.1-SNAPSHOT/, "NEW-VERSION")} RT{$0 = $0 RT} 1' file
    

    Awk 命令分解

    -v RS="</dependency>"               # sets input record separator as </dependency>
    index($0, "<groupId>...")           # for lines that have give string
    sub(/0\.1-SNAPSHOT/, "NEW-VERSION") # replace 0.1-SNAPSHOT by NEW-VERSION
    1                                   # default action to print the line
    

    简而言之,这个 awk 命令将输入​​数据分解为包含&lt;/dependency&gt; 之前的多行的记录,然后使用index 函数检查是否存在所需的groupId,并使用sub 函数替换文本。

    输出:

    <dependencies>
            <dependency>
                <groupId>com.company.xyz</groupId>
                <artifactId>xyz-xx-utils</artifactId>
                <version>NEW-VERSION</version>
            </dependency>
    
    
            <dependency>
                <groupId>com.ibm.xyz</groupId>
                <artifactId>xyz</artifactId>
                <version>56.1</version>
            </dependency>
    
    </dependencies>
    

    【讨论】:

    • 非常感谢@anubhava!你能解释一下代码吗?我还注意到控制台中的输出很完美,但实际文件没有改变,你知道为什么吗?
    • 这个想法是将 sed 的输出重定向到一个文件。默认情况下,它会打印到标准输出,就像 unix 工具倾向于做的那样。尝试使用sed -i
    • 感谢您的建议@TrentBartlem,我正在使用 anubhava 提供的代码(使用 awk 而不是 sed)我对其进行了一些更改以将输出发送到这样的文件:awk -v RS="" 'index($0, "com.company.xyz"){ sub(/0\.1-SNAPSHOT/, "NEW-VERSION")} RT{$0 = $0 RT} 1' file > otherFile.txt 它工作正常,但如果我将其更改为将输出发送到我用作输入的同一文件,则该文件最终为空。你知道我该怎么做吗?
    • @Annie 重定向发生在其他命令之前,所以如果你执行cat file &gt; file,文件会首先被截断,然后就没有什么可处理的了——你最终得到一个空文件。除非有像sed -i 这样的内置解决方案,否则您必须执行类似cat file &gt; tempfile &amp;&amp; mv tempfile file 的操作。
    • @Annie:要将更改保存回原始文件,请使用:awk -v RS="&lt;/dependency&gt;" 'index($0, "&lt;groupId&gt;com.company.xyz&lt;/groupId&gt;"){sub(/0\.1-SNAPSHOT/, "NEW-VERSION")} RT{$0 = $0 RT} 1' file &gt; file.tmp &amp;&amp; mv file.tmp file
    【解决方案3】:

    这是一个 sed 解决方案 - 比 awk 稍微笨拙一些,但也不是那么可怕。如果你把它存储在一个文件中,比如sedscr:

    /<dependency>/ {
        :start
        N
        /<\/dependency>$/!b start
        /<groupId>com.company.xyz<\/groupId>/ {
            s/\(<version>\)0\.1-SNAPSHOT\(<\/version>\)/\1NEW-VERSION\2/
        }
    }
    

    您可以使用sed -i sedscr pom.xml 运行它。它是这样工作的:

    /<dependency>/ {   # If the line matches "<dependency>"
        :start         # Label to branch to
        N              # Append next line to pattern space
    
        # If the pattern space does not end with "</dependency>", branch to start
        /<\/dependency>$/!b start
    
        # We now have the complete <dependency> element in the pattern space
    
        # If the groupId element matches "com.company.xyz"
        /<groupId>com.company.xyz<\/groupId>/ {
    
            # Substitute the version for "NEW-VERSION"
            s/\(<version>\)0\.1-SNAPSHOT\(<\/version>\)/\1NEW-VERSION\2/
        }
    }
    

    您的 sed 不起作用,因为您尝试跨换行符进行匹配,但 sed 在其模式空间中一次只有一行 - 除非您开始使用像 N(“Next”)这样的命令。即使您确实在模式空间中有多行,您也必须考虑换行并将它们与\n 匹配(并注意空格等)。

    您可以在 Bash 脚本中使用它,如下所示:

    #!/bin/bash
    
    new_version='NEW-VERSION'
    
    sed '/<dependency>/ {
        :start
        N
        /<\/dependency>$/!b start
        /<groupId>com.company.xyz<\/groupId>/ {
            s/\(<version>\)0\.1-SNAPSHOT\(<\/version>\)/\1'"$new_version"'\2/
        }
    }' pom.xml
    

    当 sed 命令不在单引号内时,这样的引用可以避免潜在的麻烦;只有$new_version 在双引号中以允许插值。

    【讨论】:

      【解决方案4】:

      以下 awk 程序已使用 gawk 和 mawk 测试,使用本页其他地方给出的 RS 简化和概括了 awk 程序。通过使用 printf,它们还可以确保保留间距。

      (a) 简化

      awk -v RS="</dependency>" '/<groupId>com.company.xyz<\/groupId>/ {
        sub(/0\.1-SNAPSHOT/, "NEW-VERSION")} {printf "%s", $0 RS}'
      

      (b) 泛化化简

      awk -v groupId="com.company.xyz" -v RS="</dependency>" '
        $0 ~ "<groupId>" groupId "</groupId>" {
          sub("<version>.*</version>", "<version>NEW-VERSION</version>")
        } 
        {printf "%s", $0 RS}'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-06-22
        • 1970-01-01
        • 2017-08-11
        • 2018-09-16
        • 2021-03-23
        • 2020-11-02
        • 2012-04-29
        相关资源
        最近更新 更多