如何在bash中从pom文件中提取版本号

3
我有一个包含以下信息的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等方面。

1
可能是如何将Maven项目版本获取到bash命令行的重复问题。 - broc.seib
7个回答

8

有些人反对使用正则表达式解析XML。你可以使用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

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


其他人可能会反对使用DOM解析Maven配置 :) +1。但我有另一个解决方案。 - Vytenis Bivainis
1
当pom文件以<project xmlns=...>开头时,选择语句需要定义命名空间。我已经添加了一个答案来说明这一点。 - Robin

6
使用Maven的方式如下:

使用Maven,您可以这样做:

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

非常好。遗憾的是,-q-l /dev/null2> /dev/null都不能说服mvn将输出与构建日志分离,因此grep似乎是唯一的方法。 - that other guy

3

试试这样:

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

输出:

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

2

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

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

使用sed,您可以编写以下内容
sed -n 's/^[[:blank:]]*<version>\([^<]\+\).*/\1/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

1
如果pom文件中有其他带有版本号的行怎么办?每个依赖和插件都会有一个版本号。 - David W.
<version/>属性在整个pom.xml文件中都可以找到。看一下commons-lang3的这个例子。有一个父级<version>,一个artifact <version>,以及三个带有<version>的依赖项。在<reporting>部分中有五个,在<build>部分中有两个。此grep将捕获它们所有。 - David W.
1
xmlstarlet这条命令在我的机器上没能正常运行,它的表现不尽如人意。相反,我用了下面这个代码很好地解决了问题 -> version=$( xmlstarlet sel -t -v '/:project/:version' pom.xml ) - Federico Gaule Palombarani

2
这篇答案来自那个人,它展示了使用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

1

或者不使用Perl兼容正则表达式,而是使用参数扩展/子字符串提取

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

我希望您能提供Perl兼容的正则表达式,如果您有可用的话。
请注意:正如David W.所指出的那样,这对于给定的示例是有效的,但是如果输入文件包含多个包含的行,则会返回多个version字符串。下面在评论中引用的完整pom.xml文件包含多个字符串。需要使用额外的循环来处理所有version行,并且如果没有唯一的标签,则无法确定所需版本是哪个version。例如,使用以下方式解析当前完整的pom.xml:
$ for i in $(grep '<version>' pom.xml); do ver=${i%<*}; ver=${ver#*>}; echo "version: $ver"; done

返回:
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

查看 commons-lang3pom.xml 文件。你的 grep 工具会捕获到几乎一打 <version> 元素。 - David W.
好的,这确实有点改变了!我只是按照给出的例子来做的。感谢提醒。我会看看它是否可挽救,如果不行我会做个记录。 - David C. Rankin

0

我的需求也类似。我们在版本末尾使用 SNAPSHOT,因此我这样做是为了找出版本号(基于 David 的答案扩展)

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接