是否有属于官方 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)。