Phân tích tên RPM thành các thành phần của nó


19

Có công cụ phân tích tên nào là một phần của gói công cụ RPM chính thức không?

Tôi có một danh sách tên tập tin. Mỗi cái là tên tệp của gói RPM. Tôi không có các gói thực tế, chỉ là tên tệp. Đối với mỗi tôi cần trích xuất tên và phiên bản của gói ($ NAME và $ VERSION). Lý do tôi cần điều này là vì tôi đang viết một kịch bản để đảm bảo rằng "yum install $ VERSION" sẽ cài đặt $ VERSION. Đây là một phần của hệ thống xây dựng các gói và xác minh chúng được tải lên đúng cách.

Danh sách tên tệp trông giống như:

$ 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

Tôi tìm thấy đoạn mã sau đây là hàm BASH thực hiện nhiệm vụ:

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

Nó hoạt động. Hầu hết. Có một số trường hợp ngoại lệ:

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

Lưu ý rằng nó không có phiên bản chính xác (phải là 1.0-99)

Tôi đang tự hỏi (1) nếu có một công cụ trong gói rpmdev thực hiện điều này một cách chính xác. (2) Nếu không, có một regex chính thức nào tôi có thể sử dụng. (3) Con trăn tương đương với regex đó là gì?

Cảm ơn trước!


Bạn có thể làm rõ nơi bạn nhận được đầu vào của bạn và định dạng nó cần không.
user9517 hỗ trợ GoFundMonica

Câu trả lời:


25

Bạn không cần phải làm bất cứ điều gì trong số này; RPM có một đối số định dạng truy vấn sẽ cho phép bạn chỉ định chính xác dữ liệu bạn muốn nhận. Nó thậm chí sẽ xuất ra mà không có kết thúc dòng nếu bạn không chỉ định chúng.

Ví dụ:

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

Danh sách đầy đủ các biến bạn có thể sử dụng có thể được lấy bằng:

rpm --querytags

Lưu ý rằng trong trường hợp RELEASE, đầu ra như 84.el6bình thường và được mong đợi, vì đây thực sự là cách các gói RPM được phiên bản khi được đóng gói bởi hoặc để phân phối.


2
Điều đó chỉ hoạt động với các gói cài đặt. Tôi muốn thao túng tên tập tin. $ 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 Đợi một chút ... Vì vậy, bạn không quan tâm những gì thực sự trong gói?
Michael Hampton

4
Tôi ước tôi biết điều đó sớm hơn. Các công cụ RPM chỉ xử lý các nội dung gói; tên tệp hoàn toàn không liên quan (và câu trả lời này sẽ không phù hợp với bạn).
Michael Hampton

1
Vui chơi phân tích cú pháp, ví dụ:libopenssl0_9_8-32bit-0.9.8j-0.26.1_0.50.1.x86_64.delta.rpm
MikeyB

5
@TomOnTime - "Điều đó chỉ hoạt động với các gói đã cài đặt" Không đúng - bạn đã bỏ lỡ tùy chọn -p trong ví dụ thứ ba: rpm --queryformat "% {NAME}% {VERSION}% {RELEASE}% {ARCH}" -qp .rpm
Sam Elstob

14

Tôi đã được cho biết cách chính thức để làm những gì tôi đang tìm kiếm trong Python:

from rpmUtils.miscutils import splitFilename

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

Tôi đã viết một chương trình Python ngắn làm những gì tôi cần. Tôi sẽ cung cấp kịch bản cho dự án rpmdev để đưa vào.


1
Các quy tắc đặt tên gói Debian rất đơn giản và khó hiểu - Tôi không biết thế giới vòng / phút đã kết thúc như thế nào trong một mớ hỗn độn như vậy. Xin vui lòng bạn có thể dán kịch bản của bạn vào câu trả lời ở đây?
Paul Hedderly

3

Tôi đã tìm ra các biểu thức chính quy phù hợp với tất cả dữ liệu mà tôi có thể kiểm tra chúng. Tôi đã phải sử dụng hỗn hợp các trận đấu tham lam và không tham lam. Điều đó nói rằng, đây là phiên bản perl và python của tôi:

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

Con tră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)

Tôi muốn có một regex xuất phát từ dự án RPM. Một cái mà tôi đã phát minh ở trên sẽ phải làm ngay bây giờ.


Điều này hầu hết tương tự như giải pháp của tôi (nhưng tránh .*trừ khi bạn THỰC SỰ muốn khớp với bất cứ điều gì). Rất vui khi thấy bạn tự tìm thấy!
mveroone

2
Tên tệp tấn công tôi là một cách xấu để có được thông tin này. Nó có thể hoạt động cho một bộ RPM do nhà cung cấp cung cấp cụ thể (vì vậy bạn có thể ổn miễn là nhà cung cấp của bạn chuẩn hóa nội dung của bên thứ ba và không bao giờ thay đổi định dạng đặt tên của họ), nhưng tôi đã thấy nhiều tệp RPM được đặt tên sáng tạo. Acrobat Reader mà tôi đã lấy từ Adobe vài giây trước là AdbeRdr9.5.5-1_i486linux_enu.rpm), nó phá vỡ phân tích cú pháp regex của bạn ở trên.
voretaq7

Thật. Nhưng Adbe sẽ không hoạt động cho bất kỳ giải pháp nào vì nó phá vỡ tiêu chuẩn tên tệp yum. (Về mặt kỹ thuật câu hỏi nên là về tên tệp yum, không phải tên tệp RPM).
TomOnTime

1

Các tệp Rpm có thể có một số tên tệp thú vị trong các trường hợp cực đoan, nhưng nhìn chung bạn có thể phân chia NVR trên các dấu gạch nối. Phần bắt là phần N (tên) của NVR có thể chứa dấu gạch nối và dấu gạch dưới, nhưng V (phiên bản) và R (bản phát hành) được đảm bảo không có bất kỳ dấu gạch nối ngoại lai nào. Vì vậy, bạn có thể bắt đầu bằng cách cắt bớt phần VR để lấy Tên.

$ 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

Dựa vào đó bạn có thể tách phần Phiên bản và Phiên bản.

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

Chỉ cần tách dấu gạch nối một lần nữa để tách phần bạn cần. Và rõ ràng làm sạch các chuỗi mở rộng tập tin vòm và vòng / phút, đó là một cho trước. Chỉ cần cung cấp cho bạn một ý tưởng về cách nó có thể được tiếp cận trong bash.


1

Sử dụng các tùy chọn -q --queryformat từ vòng / phút như đã nói trước đây, nếu bạn muốn thực hiện việc này trên gói không được cài đặt, bạn có thể chỉ định vòng / phút với -ptùy chọn, như sau:

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

ví dụ

$ 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

đưa cho tôi

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

vì vậy chỉ cần tách tên tệp là sai!

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

Vì vậy , hãy chú ý , đây không phải là chi tiết chính xác của vòng / phút, ví dụ như 1.fedorathực sự là 1.fc10trong vòng / phút.


Tôi thấy bối rối. RPM không chỉ không được cài đặt, tôi không có nó trên máy này. Tôi đang xử lý danh sách các gói và tên tệp. Điều này là cho một cái gì đó quản lý hàng tồn kho repo; Nó không có các gói thực tế.
TomOnTime

0

Nếu bạn quen thuộc với Biểu thức thông thường và / hoặc Perl, điều đó khá dễ dàng.

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

hoặc regex một mình:

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

Nếu bạn tách nó ra:

  • bất cứ điều gì ngoại trừ một dấu gạch nối, ít nhất một ký tự: [^\-]+(thoát vì dấu gạch nối có ý nghĩa đặc biệt trong các nhóm ký tự)
  • dừng trận đấu sau dấu gạch nối đầu tiên (và không phải dấu cuối cùng): [^\-]+?
  • thêm phần này vào nhóm chụp: ([^\-]+?)
  • Sau đó, một dấu gạch nối: ([^\-]+?)-
  • sau đó, bất cứ điều gì khác trong một nhóm bắt giữ khác (nhưng dấu vết .rpm): ([^\-]+?)-(.*).rpm$ (đồng đô la có nghĩa là "cuối dòng")
  • kèm theo trong một định dạng khớp thực tế: m#([^\-]+?)-(.*).rpm$#

Làm xong ! Chỉ cần lấy cả hai phần trong các biến $1$2

Nhận xét về lớp lót đầu tiên:

Tôi đã ở trong một thư mục có nhiều tập tin vòng / phút, do đó ls.

perl -p tương đương với ;

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

Điều đó giải thích rằng tôi phải đặt một chuỗi null vào $_để tránh in ngược dòng sau khi tôi đã trích xuất và in nó tùy chỉnh. Lưu ý rằng tôi có thể đã sử dụng thay thế để tránh 'hack' nhỏ này.


Điều này hoàn toàn không hoạt động trên hàng trăm tên RPM, ví dụ module-init-tools-3.9-21.el6_4.x86_64.rpm.
Nemo

0

IMHO cách vỏ đơn giản nhất là:

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

Đó là: đảo ngược từng dòng, sử dụng dấu gạch chéo chỉ phần đầu tiên ( emanelif ), sau đó sử dụng dấu gạch nối cắt tất cả trừ hai phần đầu (nghĩa là bỏ lại ESAELER bao gồm emanelif eth fo tserNOISREV ) và đảo ngược phần enil trở lại.

Với tệp ví dụ của bạn:

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

Để có được các phần khác là tập thể dục đọc cắt (1) .


0

Bạn có thể sử dụng dnf info. Dưới đây là một kịch bản Bash ví dụ để lấy các giá trị và đặt làm biến:

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

Nó sẽ cho kết quả ngay cả khi gói không được cài đặt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.