Pisahkan nama RPM ke dalam komponennya


19

Apakah ada alat parsing nama yang merupakan bagian dari paket alat RPM resmi?

Saya memiliki daftar nama file. Masing-masing adalah nama file dari paket RPM. Saya tidak memiliki paket yang sebenarnya, hanya nama file. Untuk setiap saya perlu mengekstrak nama dan versi paket ($ NAME dan $ VERSION). Alasan saya membutuhkan ini adalah saya menulis skrip yang kemudian memastikan bahwa "yum install $ VERSION" menginstal $ VERSION. Ini adalah bagian dari sistem yang membuat paket dan memverifikasi mereka diunggah dengan benar.

Daftar nama file terlihat seperti:

$ 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

Saya menemukan kode berikut yang merupakan fungsi BASH yang melakukan tugas:

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

Berhasil. Kebanyakan. Ada beberapa pengecualian:

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

Perhatikan bahwa itu tidak mendapatkan versi dengan benar (seharusnya 1,0-99)

Saya bertanya-tanya (1) apakah ada alat dalam paket rpmdev yang melakukan ini dengan benar. (2) Jika tidak, apakah ada regex resmi yang bisa saya gunakan. (3) Berapakah python yang setara dengan regex itu?

Terima kasih sebelumnya!


Bisakah Anda mengklarifikasi dari mana Anda mendapatkan input dan format yang dibutuhkan?
user9517 mendukung GoFundMonica

Jawaban:


25

Anda tidak perlu melakukan semua ini; RPM memiliki argumen format kueri yang akan memungkinkan Anda menentukan dengan tepat data yang ingin Anda terima. Bahkan akan menghasilkan tanpa akhir baris jika Anda tidak menentukannya.

Contohnya:

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

Daftar lengkap variabel yang dapat Anda gunakan dapat diperoleh dengan:

rpm --querytags

Perhatikan bahwa dalam kasus RELEASE, output seperti 84.el6adalah normal dan diharapkan, karena ini sebenarnya bagaimana paket RPM diversi ketika dikemas oleh atau untuk distribusi.


2
Itu hanya bekerja dengan paket yang diinstal. Saya ingin memanipulasi nama file. $ 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 Tunggu sebentar ... Jadi Anda tidak peduli apa yang sebenarnya ada dalam paket?
Michael Hampton

4
Saya berharap saya tahu itu lebih cepat. Alat RPM hanya berurusan dengan isi paket; nama file sama sekali tidak relevan (dan jawaban ini tidak cocok untuk Anda).
Michael Hampton

1
Bersenang-senang parsing, misalnya:libopenssl0_9_8-32bit-0.9.8j-0.26.1_0.50.1.x86_64.delta.rpm
MikeyB

5
@TomOnTime - "Itu hanya bekerja dengan paket yang diinstal" Tidak benar - Anda melewatkan opsi -p dalam contoh ketiga: rpm --queryformat "% {NAME}% {VERSION}% {RELEASE}% {ARCH}" -qp file .rpm
Sam Elstob

14

Saya telah diberi tahu cara resmi untuk melakukan apa yang saya cari adalah dengan Python:

from rpmUtils.miscutils import splitFilename

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

Saya telah menulis program Python pendek yang melakukan apa yang saya butuhkan. Saya akan menawarkan script ke proyek rpmdev untuk dimasukkan.


1
Aturan penamaan paket Debian sangat sederhana dan ketat - saya tidak tahu bagaimana dunia rpm berakhir dalam kekacauan seperti itu. Bisakah Anda menempelkan skrip ke dalam jawaban di sini?
Paul Hedderly

3

Saya menyusun ekspresi reguler yang sesuai dengan semua data yang dapat saya uji. Saya harus menggunakan campuran pertandingan serakah dan tidak serakah. Yang mengatakan, inilah versi perl dan python saya:

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)

Saya lebih suka memiliki regex yang berasal dari proyek RPM. Yang saya temukan di atas harus saya lakukan untuk saat ini.


Ini sebagian besar mirip dengan solusi saya (tetapi hindari .*kecuali Anda BENAR-BENAR ingin mencocokkan apa pun). Senang melihat bahwa Anda menemukan sendiri, meskipun!
mveroone

2
Nama file menurut saya sebagai cara yang buruk untuk mendapatkan informasi ini. Ini mungkin bekerja untuk satu set spesifik RPM yang disediakan vendor (jadi Anda mungkin baik-baik saja selama vendor Anda membakukan hal-hal pihak ketiga dan tidak pernah mengubah format penamaan mereka), tetapi saya telah melihat banyak file RPM yang diberi nama kreatif. Acrobat Reader yang saya ambil dari Adobe beberapa detik yang lalu adalah AdbeRdr9.5.5-1_i486linux_enu.rpm) yang memecah regex Anda diuraikan di atas.
voretaq7

Benar. Tetapi Adbe tidak akan bekerja untuk solusi apa pun karena melanggar standar nama file yum. (Secara teknis pertanyaannya harus tentang nama file yum, bukan nama file RPM).
TomOnTime

1

File Rpm dapat memiliki beberapa nama file yang funky dalam kasus-kasus ekstrem, tetapi umumnya Anda dapat membagi NVR pada tanda hubung. Tangkapannya adalah bagian N (nama) dari NVR dapat berisi tanda hubung dan garis bawah, tetapi V (versi) dan R (rilis) dijamin tidak memiliki tanda hubung asing. Jadi Anda bisa mulai dengan memotong bagian VR untuk mendapatkan Nama.

$ 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

Berdasarkan itu Anda dapat mengisolasi bagian Versi dan Rilis.

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

Pisahkan tanda hubung lagi untuk mengisolasi bagian yang Anda butuhkan. Dan jelas membersihkan lengkungan dan ekstensi file rpm string, yang diberikan. Hanya memberi Anda gambaran tentang bagaimana hal itu bisa didekati di bash.


1

Gunakan opsi -q --queryformat dari rpm seperti yang dikatakan sebelumnya, jika Anda ingin melakukan ini pada paket yang tidak diinstal Anda dapat menentukan rpm dengan -popsi, seperti ini:

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

misalnya

$ 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

memberi saya

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

jadi hanya memisahkan nama file itu salah!

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

jadi perhatikan , ini bukan detail rpm yang benar, misal 1.fedorasebenarnya 1.fc10di rpm.


Saya melihat kebingungan. Tidak hanya RPM tidak diinstal, saya tidak memilikinya di mesin ini. Saya sedang memproses daftar paket dan nama file. Ini untuk sesuatu yang mengelola persediaan repo; itu tidak memiliki paket yang sebenarnya.
TomOnTime

0

Jika Anda terbiasa dengan Ekspresi Reguler dan / atau Perl, itu cukup mudah.

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

atau regex saja:

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

Jika Anda membaginya, itu:

  • apa pun kecuali tanda hubung, setidaknya satu karakter: [^\-]+(melarikan diri karena tanda hubung memiliki makna khusus dalam kelompok karakter)
  • hentikan pertandingan setelah tanda hubung pertama (dan bukan yang terakhir): [^\-]+?
  • tambahkan ini ke grup tangkap: ([^\-]+?)
  • Lalu tanda hubung: ([^\-]+?)-
  • maka hal lain dalam kelompok tangkap lain (tetapi tertinggal .rpm): ([^\-]+?)-(.*).rpm$ (dolar berarti "ujung jalur")
  • melampirkan daripada dalam format pencocokan praktis: m#([^\-]+?)-(.*).rpm$#

Selesai! Hanya mendapatkan kedua bagian dalam variabel $1dan$2

Komentar pada liner pertama:

Saya berada di direktori dengan banyak file rpm, karenanya ls.

perl -p setara dengan;

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

Yang menjelaskan bahwa saya harus memasukkan null-string $_untuk menghindari perl mencetak kembali garis setelah saya mengekstrak dan mencetaknya. Perhatikan bahwa saya bisa menggunakan substitusi untuk mencegah 'peretasan' kecil ini.


Ini tidak berfungsi sama sekali pada ratusan nama RPM, mis module-init-tools-3.9-21.el6_4.x86_64.rpm.
Nemo

0

IMHO cara shell paling sederhana adalah:

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

Yaitu: membalikkan setiap baris, menggunakan slash cut hanya bagian pertama ( emanelif ), kemudian menggunakan tanda hubung semua kecuali dua bagian pertama (yaitu meninggalkan ESAELER termasuk emanelif eth fo tser dan NOISREV ) dan membalikkan enil kembali.

Dengan file contoh Anda:

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

Untuk mendapatkan bagian lain adalah latihan membaca cut (1) .


0

Anda bisa memanfaatkannya dnf info. Berikut ini contoh skrip Bash untuk mendapatkan nilai dan ditetapkan sebagai variabel:

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

Ini akan memberikan hasil bahkan jika paket tidak diinstal.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.