Analysieren Sie einen RPM-Namen in seine Komponenten

19

Gibt es ein Namensanalyse-Tool, das Teil des offiziellen RPM-Tool-Pakets ist?

Ich habe eine Liste mit Dateinamen. Jeder ist der Dateiname eines RPM-Pakets. Ich habe nicht die tatsächlichen Pakete, nur die Dateinamen. Für jedes muss ich den Paketnamen und die Version ($ NAME und $ VERSION) extrahieren. Der Grund, warum ich das brauche, ist, dass ich ein Skript schreibe, das dann sicherstellt, dass "yum install $ VERSION" $ VERSION installiert. Dies ist Teil eines Systems, das Pakete erstellt und überprüft, ob sie ordnungsgemäß hochgeladen wurden.

Die Liste der Dateinamen sieht folgendermaßen aus:

$ 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

Ich fand den folgenden Code, der eine BASH-Funktion ist, die die Aufgabe erledigt:

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

Es klappt. Meistens. Es gibt einige Ausnahmen:

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

Beachten Sie, dass es nicht die richtige Version bekommen hat (es sollte 1.0-99 sein)

Ich frage mich (1), ob das rpmdev-Paket ein Tool enthält, das dies korrekt ausführt. (2) Wenn nicht, gibt es einen offiziellen regulären Ausdruck, den ich verwenden könnte. (3) Was ist das Python-Äquivalent zu diesem Regex?

Danke im Voraus!

TomOnTime
quelle
Können Sie bitte klarstellen, woher Sie Ihre Eingaben beziehen und welches Format sie benötigen?
user9517 unterstützt GoFundMonica 26.11.13

Antworten:

25

Sie müssen nichts davon tun. RPM verfügt über ein Abfrageformatargument, mit dem Sie genau die Daten angeben können, die Sie empfangen möchten. Es wird sogar ohne Zeilenende ausgegeben, wenn Sie diese nicht angeben.

Zum Beispiel:

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

Die vollständige Liste der Variablen, die Sie verwenden können, erhalten Sie mit:

rpm --querytags

Beachten Sie, dass in diesem Fall eine RELEASEAusgabe wie 84.el6normal ist und erwartet wird, da RPM-Pakete auf diese Weise versioniert werden, wenn sie von oder für eine Distribution gepackt werden.

Michael Hampton
quelle
2
Das funktioniert nur mit installierten Paketen. Ich möchte Dateinamen manipulieren. $ 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 Warten Sie eine Minute ... Es ist Ihnen also egal, was tatsächlich im Paket enthalten ist.
Michael Hampton
4
Ich wünschte, ich hätte das früher gewusst. RPM-Tools behandeln nur den Paketinhalt. Der Dateiname ist völlig irrelevant (und diese Antwort funktioniert bei Ihnen nicht).
Michael Hampton
1
Viel Spaß beim Parsen, zum Beispiel:libopenssl0_9_8-32bit-0.9.8j-0.26.1_0.50.1.x86_64.delta.rpm
MikeyB
5
@TomOnTime - "Das funktioniert nur mit installierten Paketen" Nicht wahr - Sie haben die Option -p im dritten Beispiel verpasst: rpm --queryformat "% {NAME}% {VERSION}% {RELEASE}% {ARCH}" -qp-Datei .rpm
Sam Elstob
14

Mir wurde gesagt, dass der offizielle Weg, was ich suche, in Python ist:

from rpmUtils.miscutils import splitFilename

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

Ich habe ein kurzes Python-Programm geschrieben, das genau das tut, was ich brauche. Ich werde das Skript dem rpmdev-Projekt zur Aufnahme anbieten.

TomOnTime
quelle
1
Die Benennungsregeln für Debian-Pakete sind so einfach und unkompliziert - ich weiß nicht, wie die RPM-Welt so durcheinander gekommen ist. Könnten Sie bitte Ihr Skript in die Antwort hier einfügen?
Paul Hedderly
3

Ich habe reguläre Ausdrücke ausgearbeitet, die zu allen Daten passen, mit denen ich sie testen konnte. Ich musste eine Mischung aus gierigen und nicht gierigen Streichhölzern verwenden. Das heißt, hier ist meine Perl- und Python-Versionen:

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)

Ich hätte lieber einen regulären Ausdruck, der aus dem RPM-Projekt stammt. Das, was ich oben erfunden habe, muss fürs Erste tun.

TomOnTime
quelle
Dies ist größtenteils ähnlich wie meine Lösung (aber vermeiden .*Sie es, es sei denn, Sie möchten WIRKLICH mit etwas übereinstimmen). Schön zu sehen, dass du es selbst gefunden hast!
mveroone
2
Der Dateiname ist für mich ein schlechter Weg, um diese Informationen zu erhalten. Es funktioniert möglicherweise für einen bestimmten Satz von vom Anbieter bereitgestellten RPMs (Sie sind also möglicherweise in Ordnung, solange Ihr Anbieter die Inhalte von Drittanbietern standardisiert und das Namensformat nie ändert), aber ich habe viele RPM-Dateien mit kreativen Namen gesehen. Der Acrobat Reader, den ich vor ein paar Sekunden von Adobe geholt habe, ist AdbeRdr9.5.5-1_i486linux_enu.rpm), der Ihre Regex-Analyse oben bricht.
Voretaq7
Wahr. Aber Adbe würde für keine Lösung funktionieren, weil es den yum Dateinamenstandard bricht. (Technisch gesehen sollte die Frage nach yum-Dateinamen und nicht nach RPM-Dateinamen lauten).
TomOnTime
1

RPM-Dateien können in extremen Fällen einige unkonventionelle Dateinamen haben, aber im Allgemeinen können Sie den NVR auf die Bindestriche aufteilen. Der Haken ist, dass der N (Name) -Teil des NVR möglicherweise Bindestriche und Unterstriche enthält, aber V (Version) und R (Release) haben garantiert keine überflüssigen Bindestriche. Sie können also zunächst den VR-Teil abschneiden, um einen Namen abzuleiten.

$ 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

Darauf aufbauend können Sie den Version- und Release-Teil isolieren.

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

Teilen Sie einfach den Bindestrich erneut, um den gewünschten Teil zu isolieren. Und säubern Sie offensichtlich die vorgegebenen Zeichenfolgen für arch und rpm-Dateierweiterungen. Ich gebe Ihnen nur eine Vorstellung davon, wie es in bash angegangen werden könnte.

masta
quelle
1

Verwenden Sie die Optionen -q --queryformat von rpm wie oben beschrieben. Wenn Sie dies für ein nicht installiertes Paket tun möchten, können Sie die rpm mit der folgenden -pOption angeben :

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

z.B

$ 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

gibt mir

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

Es ist also falsch, nur den Dateinamen zu teilen!

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

so achtet , dann ist dies die Drehzahl nicht die richtigen Details, zum Beispiel 1.fedoraist eigentlich 1.fc10in der Drehzahl.

Jens Timmerman
quelle
Ich sehe die Verwirrung. Das RPM ist nicht nur nicht installiert, ich habe es auch nicht auf diesem Computer. Ich verarbeite Listen von Paketen und Dateinamen. Dies ist für etwas, das Repo-Bestände verwaltet; es hat nicht die tatsächlichen Pakete.
TomOnTime
0

Wenn Sie mit regulären Ausdrücken und / oder Perl vertraut sind, ist das ganz einfach.

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

oder der Regex alleine:

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

Wenn Sie es teilen, ist das:

  • alles andere als ein Bindestrich, mindestens ein Zeichen: [^\-]+(Escapezeichen, da Bindestrich in Zeichengruppen eine besondere Bedeutung hat)
  • stoppe das Spiel nach dem ersten Bindestrich (und nicht nach dem letzten): [^\-]+?
  • Füge dies zu einer Erfassungsgruppe hinzu: ([^\-]+?)
  • Dann ein Bindestrich: ([^\-]+?)-
  • dann irgendetwas anderes in einer anderen Erfassungsgruppe (außer dem abschließenden .rpm): ([^\-]+?)-(.*).rpm$ (der Dollar bedeutet "Zeilenende")
  • als in einem praktischen passenden Format beilegen: m#([^\-]+?)-(.*).rpm$#

Getan ! Holen Sie sich einfach beide Teile in den Variablen $1und$2

Kommentar zum ersten Einzeiler:

Ich war in einem Verzeichnis mit vielen RPM-Dateien, daher die ls.

perl -p ist äquivalent zu ;

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

Dies erklärt, dass ich eine Null-Zeichenfolge $_eingeben musste, um zu vermeiden, dass Perl die Zeile nach dem Extrahieren und benutzerdefinierten Drucken zurückdruckt. Beachten Sie, dass ich Substitutionen hätte verwenden können, um diesen kleinen "Hack" zu vermeiden.

mveroone
quelle
Dies funktioniert bei Hunderten von RPM-Namen überhaupt nicht, z module-init-tools-3.9-21.el6_4.x86_64.rpm.
Nemo
0

Meiner Meinung nach ist die einfachste Art der Shell:

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

Das heißt: Kehre jede Zeile um, indem du nur den ersten Teil ( Emanelif ) mit einem Schrägstrich schneidest , dann mit einem Bindestrich alle Teile bis auf die ersten beiden (dh hinterlasse ESAELER einschließlich Emanelif Ethfilter und NOISREV ) und kehre das Enil zurück.

Mit Ihrer Beispieldatei:

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

Um andere Teile zu bekommen, lesen Sie bitte den Schnitt (1) .

Alois Mahdal
quelle
0

Sie können nutzen dnf info. Hier ist ein Bash-Beispielskript, um Werte abzurufen und als Variable festzulegen:

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

Es wird ein Ergebnis angezeigt, auch wenn das Paket nicht installiert ist.

uboreas
quelle