将 RPM 名称解析为其组成部分

将 RPM 名称解析为其组成部分

是否有属于官方 RPM 工具包的名称解析工具?

我有一个文件名列表。每个文件名都是 RPM 包的文件名。我没有实际的包,只有文件名。对于每个包,我需要提取包名称和版本 ($NAME 和 $VERSION)。我需要这样做的原因是我正在编写一个脚本,然后确保“yum install $VERSION”安装 $VERSION。这是构建包并验证它们是否正确上传的系统的一部分。

文件名列表如下:

$ cat /tmp/packages.txt
/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial-2.8-3.el6.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial-el-2.8-3.el6.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/mercurial-2.8-3.el6.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/mercurial-hgk-2.8-3.el6.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/python-redis-2.8.0-2.el6.noarch.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/redis-2.6.16-1.el6.1.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/sei_dnsmaster-1.0-99.el6.x86_64.rpm

我发现下面的代码这是一个执行以下任务的 BASH 函数:

function parse_rpm() { RPM=$1;B=${RPM##*/};B=${B%.rpm};A=${B##*.};B=${B%.*};R=${B##*-};B=${B%-*};V=${B##*-};B=${B%-*};N=$B;echo "$N $V $R $A"; }

for i in $(</tmp/packages.txt) ; do
    parse_rpm $i
done

大部分情况下是有效的。但也有一些例外:

$ parse_rpm CentOS/6/x86_64/sei_dnsmaster-1.0-99.el6.x86_64.rpm
sei_dnsmaster 1.0 99.el6 x86_64

请注意,它没有正确获取版本(应该是 1.0-99)

我想知道 (1) rpmdev 包中是否有一个工具可以正确执行此操作。 (2) 如果没有,是否有我可以使用的官方正则表达式。 (3) 该正则表达式的 Python 等效项是什么?

提前致谢!

答案1

您不需要做任何这些;RPM 有一个查询格式参数,可以让您准确指定要接收的数据。如果您不指定行尾,它甚至会输出没有行尾的数据。

例如:

rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}" -q coreutils
rpm --queryformat "The version of %{NAME} is %{VERSION}\n" -q coreutils

rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}" -qp file.rpm

您可以使用以下方式获取完整的变量列表:

rpm --querytags

请注意,在的情况下RELEASE,像这样的输出84.el6是正常的和预期的,因为这实际上是 RPM 包在由发行版或为发行版打包时进行版本控制的方式。

答案2

有人告诉我,实现我所寻求的目标的官方方法是用 Python:

from rpmUtils.miscutils import splitFilename

(n, v, r, e, a) = splitFilename(filename)

我编写了一个简短的 Python 程序,可以满足我的需求。我将把该脚本提供给 rpmdev 项目以供纳入。

答案3

我设计了适合所有我能测试的数据的正则表达式。我必须混合使用贪婪和非贪婪匹配。话虽如此,以下是我的 perl 和 python 版本:

Perl:

#! /usr/bin/perl

foreach (@ARGV) {
    ($path, $name, $version, $release, $platform,
      @junk) = m#(.*/)*(.*)-(.*)-(.*?)\.(.*)(\.rpm)#;
    $verrel = $version . '-' . $release;

    print join("\t", $path, $name, $verrel, $version, $rev, $platform), "\n";
}

Python:

#! /usr/bin/python

import sys
import re

for x in sys.argv[1:]:
    m = re.search(r'(.*/)*(.*)-(.*)-(.*?)\.(.*)(\.rpm)', x)
    if m:
        (path, name, version, release, platform, _) = m.groups()
        path = path or ''
        verrel = version + '-' + release
        print "\t".join([path, name, verrel, version, release, platform])
    else:
        sys.stderr.write('ERROR: Invalid name: %s\n' % x)
        sys.exit(1)

我更希望使用来自 RPM 项目的正则表达式。目前只能使用上面我发明的正则表达式。

答案4

我认为最简单的 shell 方式是:

ls | rev | cut -d/ -f1 | cut -d- -f3- | rev

即:反转每一行,使用斜线剪切第一部分(埃马内利夫),然后使用连字符剪切掉除前两部分之外的所有部分(即留下艾赛勒包括埃梅利夫·埃斯·福泽噪音)并反转埃尼尔后退。

使用您的示例文件:

$ cat /tmp/packages.txt | rev | cut -d/ -f1 | cut -d- -f3- | rev
emacs-mercurial
emacs-mercurial-el
mercurial
mercurial-hgk
python-redis
redis
sei_dnsmaster
$

要获得其他部分,需要进行阅读练习切割(1)

相关内容