如何从 bash 中的 pom 文件中删除版本号

How can I cut the version number out of a pom file in bash

我有一个包含以下信息的 pom 文件:

<modelVersion>4.0.0</modelVersion>
  <groupId>com.site.camera</groupId>
  <artifactId>proj3</artifactId>
  <packaging>pom</packaging>
  <version>2.6</version>
  <name>Proj 3</name>

我正在编写一个 bash 脚本并希望能够打开此文件 (pom.xml) 并删除版本(例如本例中的 2.6)。我这样做是因为当我更新版本时,我希望脚本的其余部分也随之更新。

我尝试过的事情:

var=$(grep <version>2.6</version> pom.xml)
echo $var

请注意,我在 pom 文件中有多个版本参数。我需要这个被这个名称、包装、artifactId 等包围的特定版本。

这样试试:

var=$(grep -Po '<version>\K[^<]*' pom.xml)
echo $var

输出:

2.6
  • -P : 使用 perl 正则表达式格式
  • -o : 只打印匹配部分

最简单的方法是使用 GNU grep 的 perl 兼容正则表达式

grep -oP '<version>\K[^<]+' pom.xml

使用 sed,你会写

sed -n 's/^[[:blank:]]*<version>\([^<]\+\).*//p' pom.xml

感谢 David W. 的深思熟虑的评论:解决方案必须使用 XML 解析器。 xmlstarlet 就是这样一种工具:

ver=$( xmlstarlet sel -t -v /project/version pom.xml )

不同的是,ruby 在其标准库中附带了一个 XML 解析器:

ruby -r rexml/document -e 'puts REXML::Document.new(File.new(ARGV.shift)).elements["/project/version"].text' pom.xml

或者不用perl兼容的正则表达式使用参数expansion/substring提取:

$ var=$(grep '<version>' pom.xml); ver=${var%<*}; ver=${ver#*>}; echo $ver
2.6

如果你有 perl 兼容的 RE,我更喜欢它。

注意: 正如 David W. 所指出的。这适用于给定的示例,但会 return 多个 version 字符串,如果输入文件有多于一行包含 <version>。下面评论中引用的完整 pom.xml 文件包含 多个 <version> 字符串。需要一个额外的循环来处理所有 version 行,并且没有唯一标记,无法确定哪个 version 是所需的版本。例如解析当前完整 pom.xml 与:

$ for i in $(grep '<version>' pom.xml); do ver=${i%<*}; ver=${ver#*>}; echo "version: $ver"; done

Returns:

version: 33
version: 3.3.2
version: 4.11
version: 2.4
version: 3.2
version: 2.9.1
version: 2.5.2
version: 2.5.1
version: 2.4
version: 3.0.1
version: 2.4
version: 2.0
version: 1.7

有些人object to parsing XML with regex。以下是如何使用 xmlstarlet:

正确稳健地做到这一点
$ cat pom.xml 
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.site.camera</groupId>
  <artifactId>proj3</artifactId>
  <packaging>pom</packaging>
  <version>2.6</version>
  <name>Proj 3</name>
</project>

$ xmlstarlet sel -t -v '/project/version' pom.xml 
2.6

在 XML 工具和编辑器处理您的文档后,这同样有效:

$ cat pom.xml 
<project>
  <version><![CDATA[2]]>&#x002E;6
  </version>
</project>

$ xmlstarlet sel -t -v '/project/version' pom.xml 
2.6

编辑:作为 Doing It Right(tm) 的证明,这个解决方案在被指出会有很多不同的版本标签后仍然可以正常工作。

使用 maven,你可以这样做:

echo '${project.version}' | mvn help:evaluate | grep -v '^[[]'

我的需求也差不多。我们在版本末尾使用 SNAPSHOT,所以我这样做是为了找出版本号(大卫回答的扩展)

for i in $(grep '<version>' pom.xml); do
    #echo "$i"; 
    ver=${i%<*}; 
    ver=${ver#*>};
    if [[ $ver == *"SNAPSHOT"* ]]
        then
            echo "$ver";
    fi 

done

它给了我一个输出;我想要的

1.09-SNAPSHOT

from that other guy 说明了使用 xml 解析器的正确方法,但它无法处理 pom.xml 文件中的命名空间。

如果您的 POM 文件是这样开头的:

<?xml version="1.0" encoding="UTF-8" ?>
<project
    xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
 ...
</project>

使用时需要添加命名空间 xmlstarlet:

xmlstarlet select \
  -N x="http://maven.apache.org/POM/4.0.0" \
  --template --value-of "/x:project/x:version" \
  pom.xml