Разобрать имя 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) Что является эквивалентом Python этого регулярного выражения?

Заранее спасибо!


Можете ли вы уточнить, откуда вы берете свой вклад и формат, который он принимает, пожалуйста.
— user9517 поддержал 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";
}

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. Тот, который я изобрел выше, должен сделать сейчас.


Это в основном похоже на мое решение (но избегайте, .*если вы ДЕЙСТВИТЕЛЬНО не хотите соответствовать). Приятно видеть, что вы нашли сами!
— mveroone

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

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

1

В крайних случаях RMP-файлы могут иметь несколько прикольных имен, но обычно вы можете разделить 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

Просто разделите дефис снова, чтобы выделить нужную вам часть. И, очевидно, очистить строки расширения файлов arch и rpm, что само собой разумеющееся. Просто дать вам представление о том, как к нему можно обратиться в bash.


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

Комментарий к первому однострочнику:

Я был в директории с большим количеством файлов оборотов в минуту, следовательно 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

ИМХО самый простой способ оболочки это:

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

То есть: переверните каждую строку, используя косую черту только первой части ( emanelif ), затем используя дефис, отрежьте все, кроме первых двух частей (т.е. оставьте позади ESAELER, включая emanelif eth 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.