有一个名称parsing工具是官方RPM工具包的一部分吗?
我有一个文件名列表。 每个都是RPM包的文件名。 我没有真正的软件包,只有文件名。 对于每个我需要提取包名称和版本($ NAME和$ VERSION)。 我需要这个的原因是我正在写一个脚本,然后确保“yum install $ VERSION”安装$ VERSION。 这是构build包并validation它们已正确上载的系统的一部分。
文件名列表如下所示:
$ 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)如果没有,是否有官方的正则expression式我可以使用。 (3)什么是正则expression式的python等价物?
提前致谢!
你不需要这样做; 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
您可以使用的variables的完整列表可以通过以下方式获得:
rpm --querytags
请注意,在RELEASE的情况下,像84.el6这样的输出是正常的和预期的,因为这实际上是RPM包或版本化的版本。
我已经被告知官方的方式来做我正在寻找的是在Python中:
from rpmUtils.miscutils import splitFilename (n, v, r, e, a) = splitFilename(filename)
我已经写了一个简短的Python程序来完成我所需要的。 我将提供脚本到rpmdev项目列入。
我制定了适合所有数据的正则expression式,能够testing它们。 我不得不使用贪婪和非贪婪的比赛的混合物。 这就是说,这里是我的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项目的正则expression式。 我上面发明的那个现在必须做。
Rpm文件在极端情况下可能有一些时髦的文件名称,但通常可以将NVR拆分为连字符。 捕捉是NVR的N(名称)部分可能包含连字符和下划线,但V(版本)和R(发布)保证不会有任何无关的连字符。 所以你可以开始修剪VR部分来派生一个名字。
$ RPM=/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial-2.8-3.el6.x86_64.rpm $ echo ${RPM%-*-*} /home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial
在此基础上,您可以隔离版本和发布部分。
echo ${RPM#${RPM%-*-*}-*} 2.8-3.el6.x86_64.rpm
只需再次拆分连字符来隔离你需要的部分。 显然,清理拱和rpm文件扩展名string,这是一个给定的。 只是给你一个关于如何在bash中接近的想法。
如前所述,从rpm中使用-q –queryformat选项,如果要在未安装的软件包上执行此操作,可以使用-p选项指定rpm,如下所示:
rpm -q -p ./Downloads/polysh-0.4-1.noarch.rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n" polysh 0.4 1 noarch
例如
$ ls ./Downloads/*.rpm ./Downloads/adobe-release-x86_64-1.0-1.noarch.rpm ./Downloads/nautilus-dropbox-1.6.0-1.fedora.x86_64.rpm ./Downloads/playonlinux-yum-4-1.noarch.rpm ./Downloads/skype-4.2.0.11-fedora.i586.rpm ./Downloads/dbview-1.0.4-2.1.x86_64.rpm ./Downloads/openmotif22-libs-2.2.4-192.1.3.x86_64.rpm ./Downloads/polysh-0.4-1.noarch.rpm
给我
adobe-release-x86_64 1.0 1 noarch dbview 1.0.4 2.1 x86_64 nautilus-dropbox 1.6.0 1.fc10 x86_64 openmotif22-libs 2.2.4 192.1.3 x86_64 playonlinux-yum 4 1 noarch polysh 0.4 1 noarch skype 4.2.0.11 fc16 i586
所以只是分裂文件名是错误的!
for filename in """<paste list here>""".split(): print splitFilename(filename) ('./Downloads/adobe-release-x86_64', '1.0', '1', '', 'noarch') ('./Downloads/nautilus-dropbox', '1.6.0', '1.fedora', '', 'x86_64') ('./Downloads/playonlinux-yum', '4', '1', '', 'noarch') ('./Downloads/skype', '4.2.0.11', 'fedora', '', 'i586') ('./Downloads/dbview', '1.0.4', '2.1', '', 'x86_64') ('./Downloads/openmotif22-libs', '2.2.4', '192.1.3', '', 'x86_64') ('./Downloads/polysh', '0.4', '1', '', 'noarch')
所以要注意 ,这不是rpm的正确细节,例如1.fedora其实1.fc10 rpm中的1.fc10 。
如果您熟悉正则expression式和/或Perl,那很简单。
ls | head | perl -p -e 'm#([^\-]+?)-(.*).rpm$#; print "$1 $2\n";$_=""'
或单独的正则expression式:
m#([^\-]+?)-(.*).rpm$#
如果你分裂它是:
[^\-]+ (因为连字符在字符组中有特殊含义而被转义) [^\-]+? ([^\-]+?) ([^\-]+?)- .rpm ): ([^\-]+?)-(.*).rpm$ (美元的意思是“行尾”) m#([^\-]+?)-(.*).rpm$# 完成! 只需在variables$1和$2获取两个部分
评论第一个单行:
我在一个有许多rpm文件的目录中,因此是ls 。
perl -p相当于;
perl -e 'while(<STDIN>){ chomp($_); [YOUR CODE HERE] ; print($_); }'
这解释了我必须在$_放置一个空string,以避免在我提取并自定义打印之后,perl打印回行。 请注意,我可以使用replace来使这个小小的“黑客”变得有效。
恕我直言,最简单的shell方法是:
ls | rev | cut -d/ -f1 | cut -d- -f3- | rev
也就是说:反转每一行,使用斜杠剪切第一部分( emanelif ),然后用连字符剪切除前两部分(即留下ESAELER,包括emanelif eth fo tser和NOISREV ),然后逆转enil 。
用你的例子文件:
$ 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)阅读其他部分的练习。