AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 557350
Accepted
TomOnTime
TomOnTime
Asked: 2013-11-26 12:02:48 +0800 CST2013-11-26 12:02:48 +0800 CST 2013-11-26 12:02:48 +0800 CST

将 RPM 名称解析为其组件

  • 772

是否有作为官方 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 等价物是什么?

提前致谢!

rpm
  • 9 9 个回答
  • 18973 Views

9 个回答

  • Voted
  1. Michael Hampton
    2013-11-26T12:05:50+08:002013-11-26T12:05:50+08:00

    你不需要做任何这些;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,输出 like84.el6是正常的和预期的,因为这实际上是 RPM 包在由发行版打包或用于发行版时的版本控制方式。

    • 27
  2. Best Answer
    TomOnTime
    2013-12-04T19:55:14+08:002013-12-04T19:55:14+08:00

    有人告诉我,我正在寻找的官方方法是在 Python 中:

    from rpmUtils.miscutils import splitFilename
    
    (n, v, r, e, a) = splitFilename(filename)
    

    我编写了一个简短的 Python 程序来满足我的需要。我会将脚本提供给 rpmdev 项目以供包含。

    • 16
  3. TomOnTime
    2013-11-27T07:07:21+08:002013-11-27T07:07:21+08:00

    我制定了适合我能够测试它们的所有数据的正则表达式。我不得不混合使用贪婪和非贪婪匹配。也就是说,这是我的 perl 和 python 版本:

    珀尔:

    #! /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
  4. masta
    2014-11-14T21:08:50+08:002014-11-14T21:08:50+08:00

    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
    

    只需再次拆分连字符以隔离您需要的部分。并且显然清除了 arch 和 rpm 文件扩展名字符串,这是给定的。只是让您了解如何在 bash 中处理它。

    • 2
  5. Jens Timmerman
    2013-12-04T03:13:57+08:002013-12-04T03:13:57+08:00

    如前所述,使用 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
  6. Alois Mahdal
    2016-03-06T02:07:47+08:002016-03-06T02:07:47+08:00

    恕我直言,最简单的外壳方式是:

    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
    $
    

    要获得其他部分是阅读cut(1)的练习。

    • 1
  7. mveroone
    2013-11-27T00:27:12+08:002013-11-27T00:27:12+08:00

    如果您熟悉正则表达式和/或 Perl,那很容易。

     ls | head | perl -p -e 'm#([^\-]+?)-(.*).rpm$#; print "$1 $2\n";$_=""' 
    

    或单独的正则表达式:

    m#([^\-]+?)-(.*).rpm$#
    

    如果你拆分它,那就是:

    • 除了连字符之外的任何东西,至少一个字符:([^\-]+因为连字符在字符组中具有特殊含义而转义)
    • 在第一个连字符(而不是最后一个)之后停止比赛:[^\-]+?
    • 将此添加到捕获组:([^\-]+?)
    • 然后是一个连字符:([^\-]+?)-
    • 然后是另一个捕获组中的任何其他内容(但尾随.rpm):(([^\-]+?)-(.*).rpm$ 美元表示“行尾”)
    • 附上比实际匹配格式:m#([^\-]+?)-(.*).rpm$#

    完毕 !只需在变量中获取两个部分,$1然后$2

    评论第一个单行:

    我在一个包含许多 rpm 文件的目录中,因此ls.

    perl -p相当于;

    perl -e 'while(<STDIN>){ chomp($_);  [YOUR CODE HERE] ; print($_); }' 
    

    这解释了我必须放入一个空字符串$_以避免在我提取并自定义打印该行之后 perl 打印回该行。请注意,我可以使用替换来避免这个小“黑客”。

    • 0
  8. uboreas
    2019-10-08T07:16:08+08:002019-10-08T07:16:08+08:00

    您可以利用dnf info. 这是一个获取值并设置为变量的示例 Bash 脚本:

    function dnfinfo() {
       dnf info "$(echo "${1}" | sed 's/\.rpm$//g')"
    }
    
    function splitname() {
       eval $(
         dnfinfo "${1}" | \
         grep "^Arch\|^Name\|^Release\|^Version" | \
         sort | \
         awk -F": " {'print "\""$2"\""'} | \
         tr "\n" " " | \
         awk {'print "xarch="$1"~xname="$2"~xrel="$3"~xver="$4'} | \
         tr "~" "\n"
       )
    }
    
    splitname "tcpdump-4.9.2-5.el8.x86_64.rpm"
    echo "${xname} ${xver} ${xrel} ${xarch}"
    

    即使未安装软件包,它也会给出结果。

    • 0
  9. Hannes Stoolmann
    2020-09-03T02:46:48+08:002020-09-03T02:46:48+08:00

    到目前为止,最简单的方法是创建一个可以做一件事的正则表达式,工作;-) Substring Regex w're disc.:

    s/^(?:\w{1})(?:-?\w+?\S+?-?){1,}?(\d+[\:|\.]\d+\S+)/$1/g
    

    那是 perl 中的子字符串正则表达式!

    例子:

    echo  bonnie-++sdsdsœ@@œ=gcc-++++_sded-sdsdsd-fcc-gcc-c++-4.8.5-36.0.1.el7_6.2.x86_64|perl  -pe 's/^(?:\w{1})(?:-?\w+?\S+?-?){1,}?(\d+[\:|\.]\d+\S+)/$1/g'
    

    输出: 4.8.5-36.0.1.el7_6.2.x86_64

    所以版本是对的。正则表达式在一行中涵盖了 99.9% 的 RPM 包名称;-)

    简短说明:(?:) 非捕获组(我不想要这部分 -> 使用它来提高速度。总是)

    \w+:单词字符(包括_)

    ? 可选匹配

    \S+:非空格字符

    {1,} 不捕获-匹配整个组 1 个或多个

    Worx 为你和我!

    • 0

相关问题

  • 将 rpm 命令转换为 dpkg

  • 通过 RPM 管理配置?

  • 用于维护 yum 存储库的工具

  • 用于 centos 的 Python 源 RPMS?

  • 可以使用 easy_install 和 bdist_rpm 安装吗?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve