Bir RPM adını bileşenlerine ayrıştırma


19

Resmi RPM araç paketinin bir parçası olan bir ad ayrıştırma aracı var mı?

Bir dosya adları listem var. Her biri bir RPM paketinin dosya adıdır. Gerçek paketlerim yok, sadece dosya isimleri. Her biri için paket adını ve sürümünü ($ NAME ve $ VERSION) ayıklamam gerekiyor. Bu ihtiyacım nedeni ben daha sonra "yum install $ VERSION" $ VERSION yükler emin olun bir komut dosyası yazıyorum. Bu, paketleri oluşturan ve düzgün şekilde yüklendiğini doğrulayan bir sistemin parçasıdır.

Dosya adları listesi şuna benzer:

$ 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

Ben görevi yapan bir BASH işlevi olan aşağıdaki kodu buldum :

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

İşe yarıyor. Çoğunlukla. Bazı istisnalar vardır:

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

Sürümü doğru şekilde almadığına dikkat edin (1.0-99 olmalıdır)

(1) rpmdev paketinde bunu doğru yapan bir araç olup olmadığını merak ediyorum. (2) Değilse, kullanabileceğim resmi bir regex var mı? (3) Bu normal ifadenin python eşdeğeri nedir?

Şimdiden teşekkürler!


Girişinizi nereden aldığınızı ve lütfen formatı netleştirebilir misiniz?
user9517, GoFundMonica

Yanıtlar:


25

Bunların hiçbirini yapmanız gerekmez; RPM, tam olarak almak istediğiniz verileri belirtmenize olanak tanıyan bir sorgu biçimi bağımsız değişkenine sahiptir. Hatta belirtmezseniz, satır sonları olmadan bile çıktı alır.

Örneğin:

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

Kullanabileceğiniz değişkenlerin tam listesi aşağıdakilerle elde edilebilir:

rpm --querytags

Bu durumda RELEASE, çıktı gibi 84.el6normal ve beklenen bir durum olduğuna dikkat edin , çünkü RPM paketlerinin bir dağıtım tarafından veya dağıtım için paketlendiğinde bu şekilde sürümlendirilir.


2
Bu yalnızca kurulu paketlerle çalışır. Dosya adlarını değiştirmek istiyorum. $ rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}" -q CentOS/6/x86_64/sei_dnsmaster-1.0-84.el6.x86_64.rpm package CentOS/6/x86_64/sei_dnsmaster-1.0-84.el6.x86_64.rpm is not installed
TomOnTime

@TomOnTime Bir dakika ... Yani pakette ne olduğunu umursamıyor musun?
Michael Hampton

4
Keşke bunu daha erken bilseydim. RPM araçları yalnızca paket içeriğiyle ilgilenir; dosya adı tamamen ilgisizdir (ve bu cevap sizin için işe yaramaz).
Michael Hampton

1
Örneğin, ayrıştırma eğlenin:libopenssl0_9_8-32bit-0.9.8j-0.26.1_0.50.1.x86_64.delta.rpm
MikeyB

5
@TomOnTime - "Bu yalnızca yüklü paketlerle çalışır" Doğru değil - üçüncü örnekte -p seçeneğini kaçırdınız: rpm --queryformat "% {NAME}% {VERSION}% {RELEASE}% {ARCH}" -qp dosyası .rpm
Sam Elstob

14

Bana aradığımı yapmanın resmi yolunun Python'da olduğu söylendi:

from rpmUtils.miscutils import splitFilename

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

İhtiyacım olanı yapan kısa bir Python programı yazdım. Komut dosyasını rpmdev projesine dahil edeceğim.


1
Debian paket adlandırma kuralları çok basit ve sağlamdır - rpm dünyasının nasıl böyle bir karmaşa içinde olduğunu bilmiyorum. Lütfen betiğinizi buradaki cevaba yapıştırır mısınız?
Paul Hedderly

3

Test edebildiğim tüm verilere uyan düzenli ifadeler üzerinde çalıştım. Açgözlü ve açgözlü olmayan maçların bir karışımını kullanmak zorunda kaldım. Yani, benim perl ve python sürümleri:

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 projesinden gelen bir normal ifade almayı tercih ederim. Yukarıda icat ettiğim kişinin şimdilik yapması gerekecek.


Bu çoğunlukla benim çözümümden çok benzer (ancak .*GERÇEKTEN bir şey eşleştirmek istemediğiniz sürece kaçının ). Yine de kendiniz bulduğunuzu görmek güzel!
mveroone

2
Dosya adı bana bu bilgiyi almanın kötü bir yolu olarak bakıyor. Tedarikçinin sağladığı belirli bir RPM kümesi için işe yarayabilir (bu nedenle satıcınız üçüncü tarafları standartlaştırdığı ve adlandırma formatını asla değiştirmediği sürece sorun olmayabilir), ancak çok sayıda yaratıcı olarak adlandırılmış RPM dosyası gördüm. Birkaç saniye önce Adobe'den aldığım Acrobat Reader AdbeRdr9.5.5-1_i486linux_enu.rpm) yukarıdaki regex ayrıştırma işleminizi bozan.
voretaq7

Doğru. Ancak Adbe herhangi bir çözüm için işe yaramaz çünkü yum dosya adı standardını bozar. (Teknik olarak soru RPM dosya adları ile değil yum dosya adları ile ilgili olmalıdır).
TomOnTime

1

RPM dosyalarının aşırı durumlarda bazı funky dosya adları olabilir, ancak genellikle NVR'yi tire işaretlerine bölebilirsiniz. Yakalama, NVR'nin N (ad) kısmı tire ve alt çizgi içerebilir, ancak V (sürüm) ve R (serbest bırakma) herhangi bir yabancı tire içermediği garanti edilir. Böylece, bir Ad türetmek için VR bölümünü keserek başlayabilirsiniz.

$ 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

Buna dayanarak Sürüm ve Yayın bölümünü izole edebilirsiniz.

echo ${RPM#${RPM%-*-*}-*}
2.8-3.el6.x86_64.rpm

İhtiyacınız olan parçayı izole etmek için kısa çizgiyi tekrar bölün. Ve belli ki verilen kemer ve rpm dosya uzantısı dizelerini temizleyin. Sadece size bash'da nasıl yaklaşılabileceği hakkında bir fikir veriyor.


1

Daha önce de belirtildiği gibi rpm'den -q --queryformat seçeneklerini kullanın, bunu kurulu olmayan bir pakette yapmak istiyorsanız, rpm'yi aşağıdaki seçenekle belirleyebilirsiniz -p:

rpm -q -p ./Downloads/polysh-0.4-1.noarch.rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n"
polysh 0.4 1 noarch

Örneğin

$ 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

bana verir

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

bu yüzden sadece dosya adını bölmek yanlış!

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')

bu yüzden dikkat , bu rpm doğru detaylar değildir, örneğin 1.fedoraaslında 1.fc10rpm.


Karışıklığı görüyorum. RPM sadece yüklü değil, aynı zamanda bu makinede de yok. Paket listelerini ve dosya adlarını işliyorum. Bu, repo stoklarını yöneten bir şey içindir; gerçek paketleri yok.
TomOnTime

0

Normal İfadeler ve / veya Perl hakkında bilginiz varsa, bu oldukça kolaydır.

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

veya tek başına normal ifade:

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

Eğer ayırırsanız:

  • Tire'den başka bir şey, en az bir karakter: [^\-]+(tire, karakter gruplarında özel bir anlama sahip olduğundan kaçtı)
  • ilk tireden sonra (sonuncusu değil) maçı durdurun: [^\-]+?
  • bunu bir yakalama grubuna ekleyin: ([^\-]+?)
  • Sonra kısa çizgi: ([^\-]+?)-
  • başka bir yakalama grubundaki (ancak sondaki .rpm) herhangi bir şey : ([^\-]+?)-(.*).rpm$ (dolar "satır sonu" anlamına gelir)
  • pratik bir eşleme biçiminde olduğundan daha fazlasını ekleyin: m#([^\-]+?)-(.*).rpm$#

Yapıldı! Değişkenlerde her iki parçayı da almanız $1ve$2

İlk tek astar hakkında yorum:

Birçok rpm dosyası olan bir dizindeydim, dolayısıyla ls.

perl -p eşittir;

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

Hangi açıkladı $_ve özel baskı sonra satır geri perl yazdırma önlemek için bir boş dizesi koymak zorunda olduğunu açıklar . Ben bu küçük 'kesmek' önlemek için ikame kullanabilirsiniz olabilir unutmayın.


Bu, örneğin, yüzlerce RPM adında çalışmaz module-init-tools-3.9-21.el6_4.x86_64.rpm.
Nemo

0

IMHO en basit kabuk yolu:

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

Şudur: çizgi kesim sadece ilk bölümü (kullanarak her satırı ters emanelif sonra tire tüm kesti ama ilk iki parça (arkasında yani bırakın kullanarak) ESAELER dahil tser fo eth emanelif ve NOISREV ) ve ters enil geri.

Örnek dosyanızla:

$ 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
$

Diğer kısımları almak okuma kesiminde alıştırmadır (1) .


0

Siz de kullanabilirsiniz dnf info. Değerleri almak ve değişken olarak ayarlamak için örnek bir Bash betiği:

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}"

Paket kurulu olmasa bile sonuç verecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.