Розберіть ім'я RPM на його компоненти


19

Чи є інструмент аналізу імен, який є частиною офіційного пакету інструментів 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) Який епітонний еквівалент цього регулярного виразу?

Спасибі заздалегідь!


Чи можете ви уточнити, звідки ви берете інформацію та формат, який він потребує, будь ласка.
користувач9517 підтримуєGoFundMonica

Відповіді:


25

Вам нічого не потрібно робити цього; 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, як, наприклад, вихідний результат 84.el6є нормальним та очікуваним, оскільки це фактично переоформлення пакетів RPM при упаковці через або для розповсюдження.


2
Це працює лише з встановленими пакетами. Я хочу маніпулювати іменами. $ 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 Почекайте хвилинку ... Тож вам не байдуже, що насправді є в пакеті?
Майкл Хемптон

4
Я хотів би, щоб я знав це раніше. Інструменти RPM стосуються лише вмісту пакета; ім'я файлу абсолютно не має значення (і ця відповідь не підійде для вас).
Майкл Хемптон

1
Приємно libopenssl0_9_8-32bit-0.9.8j-0.26.1_0.50.1.x86_64.delta.rpm
розбирайте

5
@TomOnTime - "Це працює лише з встановленими пакетами" Неправда - ви пропустили опцію -p у третьому прикладі: rpm --queryformat "% {NAME}% {VERSION}% {RELEASE}% {ARCH}" -qp файл .rpm
Сем Елстоб

14

Мені сказали, що офіційний спосіб робити те, що я шукаю, - це в Python:

from rpmUtils.miscutils import splitFilename

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

Я написав коротку програму Python, яка робить все, що мені потрібно. Я запропоную сценарій проекту rpmdev для включення.


1
Правила іменування пакунків Debian настільки прості та легкі - я не знаю, як світ rpm опинився в такому безладі. Чи можете ви вставити свій скрипт у відповідь тут?
Пол Хеддерлі

3

Я розробляв регулярні вирази, які відповідають усім даним, з якими я міг їх перевірити. Довелося використовувати суміш жадібних та не жадібних сірників. Це сказав, ось моя версія perl та 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";
}

Пітон:

#! /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. Те, що я вигадав вище, доведеться робити зараз.


Це здебільшого схоже на моє рішення (але уникайте, .*якщо ви дійсно не хочете нічого відповідати) Приємно бачити, що ти знайшов сам, хоча!
mveroone

2
Ім'я файлу вважає мене поганим способом отримання цієї інформації. Це може працювати для певного набору RPM, наданих постачальником (тому ви можете бути в порядку, якщо ваш постачальник стандартизує сторонні речі і ніколи не змінює їх формат іменування), але я бачив безліч файлів RPM, творчо названих. Acrobat Reader, який я схопив від Adobe кілька секунд тому AdbeRdr9.5.5-1_i486linux_enu.rpm), який порушує ваш синтаксичний аналіз вище.
voretaq7

Правда. Але Adbe не працює для жодного рішення, оскільки воно порушує стандарт файлу yum. (Технічно питання має стосуватися іменних імен файлів, а не файлів RPM).
TomOnTime

1

У крайніх випадках файли Rpm можуть мати кілька прикольних імен файлів, але, як правило, ви можете розділити NVR на дефіси. Захоплення N (ім'я) частини NVR може містити дефіси та підкреслення, але 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

Просто розділіть дефіс ще раз, щоб виділити потрібну вам частину. І очевидно, очистіть рядки розширення файлів для арки та rpm, що є заданим. Просто даю вам уявлення про те, як можна було б підійти до гри.


1

Використовуйте параметри -q --queryformat від rpm, як було сказано раніше, якщо ви хочете зробити це в не встановленому пакеті, ви можете вказати rpm за допомогою -pпараметра, як це:

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

тому зверніть увагу , це не правильні деталі обертів, наприклад, 1.fedoraце фактично 1.fc10в оборотах в хвилину.


Я бачу плутанину. RPM не тільки не встановлений, я не маю його на цій машині. Я обробляю списки пакетів та назви файлів. Це для чогось, що управляє товарно-матеріальними запасами; він не має фактичних пакетів.
TomOnTime

0

Якщо ви знайомі з регулярними виразами та / або 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($_); }' 

Що пояснює, що мені довелося вставити нульовий рядок, $_щоб уникнути друку рядків назад після того, як я вилучив його та роздрукував на замовлення. Зауважте, що я міг би використати заміни, щоб оминути цей маленький "хак".


Це зовсім не працює на сотнях імен RPM, наприклад module-init-tools-3.9-21.el6_4.x86_64.rpm.
Немо

0

IMHO найпростіший спосіб оболонки:

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

Тобто: переверніть кожен рядок, використовуючи нарізану косу рису лише першу частину ( emanelif ), потім за допомогою дефісу виріжте всі, крім перших двох частин (тобто залиште позаду ESAELER, включаючи emanelif et fo tser і NOISREV ) і поверніть еніл назад.

З вашим прикладом файлу:

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

Отримати інші частини - вправа на читання вирізання (1) .


0

Ви можете використовувати 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}"

Це дасть результат, навіть якщо пакет не встановлений.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.