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

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

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

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

TomOnTime
источник
Это в основном похоже на мое решение (но избегайте, .*если вы ДЕЙСТВИТЕЛЬНО не хотите соответствовать). Приятно видеть, что вы нашли сами!
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.

Masta
источник
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($_); }' 

Это объясняет, что мне пришлось ввести пустую строку, $_чтобы избежать перл-печати строки после того, как я ее распаковал и распечатал на заказ. Обратите внимание, что я мог бы использовать замены, чтобы избежать этого маленького взлома.

mveroone
источник
Это не работает вообще на сотнях имен 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}"

Это даст результат, даже если пакет не установлен.

uboreas
источник