Analizzare un nome RPM nei suoi componenti


19

Esiste uno strumento di analisi dei nomi che fa parte del pacchetto di strumenti RPM ufficiale?

Ho un elenco di nomi di file. Ognuno è il nome file di un pacchetto RPM. Non ho i pacchetti reali, solo i nomi dei file. Per ognuno ho bisogno di estrarre il nome e la versione del pacchetto ($ NAME e $ VERSION). Il motivo per cui ho bisogno di questo è che sto scrivendo uno script che quindi si assicura che "yum install $ VERSION" installi $ VERSION. Questo fa parte di un sistema che crea pacchetti e verifica che siano caricati correttamente.

L'elenco dei nomi dei file è simile a:

$ 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

Ho trovato il seguente codice che è una funzione BASH che svolge il compito:

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

Funziona. Soprattutto. Ci sono alcune eccezioni:

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

Si noti che non ha ottenuto la versione correttamente (dovrebbe essere 1.0-99)

Mi chiedo (1) se c'è un tool nel pacchetto rpmdev che lo fa correttamente. (2) In caso contrario, esiste una regex ufficiale che potrei usare. (3) Qual è l'equivalente in pitone di quel regex?

Grazie in anticipo!


Puoi chiarire da dove stai ricevendo i tuoi input e il formato che utilizza, per favore.
user9517 supporta GoFundMonica il

Risposte:


25

Non devi fare nulla di tutto ciò; RPM ha un argomento in formato query che ti permetterà di specificare esattamente i dati che desideri ricevere. Verrà anche emesso senza terminazioni di riga se non le specifichi.

Per esempio:

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

L'elenco completo delle variabili che è possibile utilizzare può essere ottenuto con:

rpm --querytags

Si noti che, nel caso di RELEASE, output like 84.el6è normale e previsto, poiché in questo modo i pacchetti RPM sono sottoposti a versione quando vengono impacchettati da o per una distribuzione.


2
Funziona solo con i pacchetti installati. Voglio manipolare i nomi dei 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 Aspetta un minuto ... Quindi non ti importa cosa c'è realmente nel pacchetto?
Michael Hampton

4
Vorrei averlo saputo prima. Gli strumenti RPM si occupano solo del contenuto del pacchetto; il nome file è completamente irrilevante (e questa risposta non funzionerà per te).
Michael Hampton

1
Divertiti ad analizzare, ad esempio:libopenssl0_9_8-32bit-0.9.8j-0.26.1_0.50.1.x86_64.delta.rpm
MikeyB,

5
@TomOnTime - "Funziona solo con i pacchetti installati" Non è vero: hai perso l'opzione -p nel terzo esempio: rpm --queryformat "% {NAME}% {VERSION}% {RELEASE}% {ARCH}" -qp file .rpm
Sam Elstob,

14

Mi è stato detto che il modo ufficiale di fare ciò che sto cercando è in Python:

from rpmUtils.miscutils import splitFilename

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

Ho scritto un breve programma Python che fa quello che mi serve. Offrirò la sceneggiatura al progetto rpmdev per l'inclusione.


1
Le regole di denominazione dei pacchetti Debian sono così semplici e strane: non so come il mondo rpm sia finito in un tale casino. Per favore, potresti incollare il tuo script nella risposta qui?
Paul Hedderly,

3

Ho elaborato espressioni regolari che si adattano a tutti i dati con cui sono stato in grado di testarli. Ho dovuto usare un mix di partite golose e non golose. Detto questo, ecco le mie versioni perl e 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";
}

Pitone:

#! /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)

Preferirei avere una regex che proviene dal progetto RPM. Quello che ho inventato sopra dovrà fare per ora.


Questo è per lo più simile alla mia soluzione (ma evita a .*meno che tu non voglia VERAMENTE abbinare qualcosa). Bello vedere che hai trovato da solo, però!
mveroone,

2
Il nome del file mi sembra un brutto modo per ottenere queste informazioni. Potrebbe funzionare per un set specifico di RPM forniti dal fornitore (quindi potresti essere OK fino a quando il tuo fornitore standardizza le cose di terze parti e non cambia mai il loro formato di denominazione), ma ho visto molti file RPM con nomi creativi. L'Acrobat Reader che ho preso da Adobe pochi secondi fa è AdbeRdr9.5.5-1_i486linux_enu.rpm) che interrompe la tua regex analizzando sopra.
voretaq7,

Vero. Ma Adbe non funzionerebbe per nessuna soluzione perché infrange lo standard del nome file yum. (Tecnicamente la domanda dovrebbe riguardare i nomi di file yum, non i nomi di file RPM).
TomOnTime

1

I file Rpm possono avere nomi di file funky in casi estremi, ma generalmente è possibile dividere l'NVR sui trattini. Il problema è che la parte N (nome) dell'NVR può contenere trattini e trattini bassi, ma è garantito che V (versione) e R (versione) non abbiano trattini estranei. Quindi puoi iniziare tagliando la porzione VR per ricavare un nome.

$ 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

Partendo da questo è possibile isolare la parte Versione e Rilascio.

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

Dividi nuovamente il trattino per isolare la parte che ti serve. E ovviamente ripulire le stringhe di estensione del file arch e rpm, che è un dato di fatto. Ti sto solo dando un'idea di come potrebbe essere affrontato in Bash.


1

Usa le opzioni -q --queryformat di rpm come detto prima, se vuoi farlo su un pacchetto non installato puoi specificare l'rpm con l' -popzione, in questo modo:

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

per esempio

$ 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

mi da

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

quindi solo dividere il nome del file è sbagliato!

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

quindi attenzione , questi non sono i dettagli corretti del numero di giri, ad es. 1.fedoraè effettivamente 1.fc10nel numero di giri.


Vedo la confusione. Non solo l'RPM non è installato, ma non l'ho su questa macchina. Sto elaborando elenchi di pacchetti e nomi di file. Questo è per qualcosa che gestisce gli inventari dei pronti contro termine; non ha i pacchetti attuali.
TomOnTime

0

Se hai familiarità con le espressioni regolari e / o il Perl, è abbastanza facile.

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

o la sola regex:

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

Se lo dividi questo è:

  • tutt'altro che un [^\-]+trattino , almeno un carattere: (fuggito perché il trattino ha un significato speciale nei gruppi di caratteri)
  • ferma la partita dopo il primo trattino (e non l'ultimo): [^\-]+?
  • aggiungilo a un gruppo di acquisizione: ([^\-]+?)
  • Quindi un trattino: ([^\-]+?)-
  • quindi qualsiasi altra cosa in un altro gruppo di acquisizione (ma il trailing .rpm): ([^\-]+?)-(.*).rpm$ (il dollaro significa "fine linea")
  • allegare che in un pratico formato di corrispondenza: m#([^\-]+?)-(.*).rpm$#

Fatto ! Basta avere entrambe le parti nelle variabili $1e$2

Commento sul primo one-liner:

Ero in una directory con molti file rpm, quindi il ls.

perl -p è equivalente a ;

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

Il che spiega che ho dovuto inserire una stringa null $_per evitare che Perl stampasse la riga dopo averla estratta e stampata su misura. Nota che avrei potuto usare le sostituzioni per evitare questo piccolo "hack".


Questo non funziona affatto su centinaia di nomi RPM, ad es module-init-tools-3.9-21.el6_4.x86_64.rpm.
Nemo,

0

IMHO il modo più semplice di shell è:

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

Cioè: invertire ogni riga, usando il taglio della barra solo la prima parte ( emanelif ), quindi usando il trattino per tagliare tutte tranne le prime due parti (ovvero lasciare indietro ESAELER incluso emanelif eth fo tser e NOISREV ) e invertire indietro l' enil .

Con il tuo file di esempio:

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

Ottenere altre parti è un esercizio di lettura (1) .


0

Puoi utilizzare dnf info. Ecco un esempio di script Bash per ottenere valori e impostare come variabile:

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

Darà un risultato anche se il pacchetto non è installato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.