แยกชื่อ 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) ถ้าไม่มีจะมี regex อย่างเป็นทางการที่ฉันสามารถใช้ได้ (3) python ที่เทียบเท่ากับ regex นั้นคืออะไร

ขอบคุณล่วงหน้า!


คุณช่วยอธิบายที่คุณได้รับข้อมูลของคุณจากและรูปแบบที่จะโปรด
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 รอสักครู่ ... ดังนั้นคุณไม่สนใจสิ่งที่อยู่ในแพคเกจจริงเหรอ?
Michael Hampton

4
ฉันหวังว่าฉันจะรู้ว่าไม่ช้าก็เร็ว เครื่องมือ RPM นั้นจัดการกับเนื้อหาของแพ็คเกจเท่านั้น ชื่อไฟล์นั้นไม่เกี่ยวข้องอย่างสมบูรณ์ (และคำตอบนี้จะไม่เหมาะกับคุณ)
Michael Hampton

1
ขอให้สนุกกับการวิเคราะห์คำตัวอย่าง:libopenssl0_9_8-32bit-0.9.8j-0.26.1_0.50.1.x86_64.delta.rpm
MikeyB

5
@TomOnTime - "ใช้งานได้กับแพ็คเกจที่ติดตั้งเท่านั้น" ไม่เป็นความจริง - คุณพลาดตัวเลือก -p ในตัวอย่างที่สาม: rpm --queryformat "% {NAME}% {VERSION}% {RELEASE}% {ARCH}" -qp .rpm
Sam Elstob

14

ฉันได้รับการบอกวิธีการอย่างเป็นทางการในการทำสิ่งที่ฉันต้องการคือ Python:

from rpmUtils.miscutils import splitFilename

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

ฉันเขียนโปรแกรม Python สั้น ๆ ที่ทำในสิ่งที่ฉันต้องการ ฉันจะเสนอสคริปต์ให้กับโครงการ rpmdev เพื่อการรวม


1
กฎการตั้งชื่อแพ็คเกจเดเบียนนั้นเรียบง่ายและไม่ซับซ้อน - ฉันไม่รู้ว่าโลกรอบต่อนาทีได้เกิดความยุ่งเหยิงเช่นไร คุณช่วยวางสคริปต์ของคุณลงในคำตอบได้ไหม?
Paul Hedderly

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)

ฉันอยากมี regex ที่มาจากโครงการ RPM คนที่ฉันประดิษฐ์ข้างต้นจะต้องทำตอนนี้


ส่วนใหญ่คล้ายกับโซลูชันของฉัน (แต่หลีกเลี่ยง.*ถ้าคุณไม่ต้องการจับคู่อะไรเลย) ยินดีที่ได้พบว่าคุณพบด้วยตัวเอง!
mveroone

2
ชื่อไฟล์ทำให้ฉันเป็นวิธีที่ไม่ดีในการรับข้อมูลนี้ อาจใช้งานได้กับ RPM ที่ผู้ให้บริการกำหนดไว้เท่านั้น (ดังนั้นคุณอาจตกลงได้ตราบใดที่ผู้ขายของคุณสร้างมาตรฐานให้กับบุคคลที่สามและไม่เคยเปลี่ยนรูปแบบการตั้งชื่อ) แต่ฉันเห็นไฟล์ RPM ที่ตั้งชื่ออย่างสร้างสรรค์มากมาย Acrobat Reader ที่ฉันคว้ามาจาก Adobe เมื่อไม่กี่วินาทีที่ผ่านมาคือAdbeRdr9.5.5-1_i486linux_enu.rpm) ซึ่งแบ่งการแยก regex ของคุณด้านบนออก
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

เพียงแค่แยกเครื่องหมายยัติภังค์อีกครั้งเพื่อแยกส่วนที่คุณต้องการ และเห็นได้ชัดว่าล้างสตริงส่วนขยายของไฟล์ arch และ rpm ซึ่งกำหนดไว้ เพียงแค่ให้คุณทราบว่ามันสามารถเข้าหาทุบตีได้อย่างไร


1

ใช้ตัวเลือก -q --queryformat จากรอบต่อนาทีตามที่กล่าวไว้ก่อนหน้านี้หากคุณต้องการทำสิ่งนี้บนแพ็คเกจที่ไม่ได้ติดตั้งคุณสามารถระบุรอบต่อนาทีพร้อม-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 แล้วฉันไม่ได้ติดตั้งในเครื่องนี้ ฉันกำลังประมวลผลรายการแพคเกจและชื่อไฟล์ นี่คือสิ่งที่จัดการสินค้าคงคลัง repo; มันไม่มีแพ็คเกจจริง
TomOnTime

0

หากคุณคุ้นเคยกับนิพจน์ทั่วไปและ / หรือ Perl นั่นเป็นเรื่องง่าย

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

หรือ regex เพียงอย่างเดียว:

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

หากคุณแยกเป็น:

  • อะไรก็ได้ยกเว้นยัติภังค์อักขระอย่างน้อยหนึ่งตัว: [^\-]+(ยกเว้นเพราะเครื่องหมายขีดคั่นมีความหมายพิเศษในกลุ่มอักขระ)
  • หยุดการแข่งขันหลังจากยัติภังค์แรก (และไม่ใช่ตัวสุดท้าย): [^\-]+?
  • เพิ่มลงในกลุ่มการจับ: ([^\-]+?)
  • จากนั้นจึงใช้เครื่องหมายยัติภังค์: ([^\-]+?)-
  • ดังนั้นสิ่งอื่นใดในกลุ่มการจับกุมอื่น (แต่จะตามมาด้วย.rpm): ([^\-]+?)-(.*).rpm$ (ดอลลาร์หมายถึง "จุดสิ้นสุดของบรรทัด")
  • ล้อมรอบกว่าในรูปแบบการจับคู่ที่ใช้งานได้จริง: m#([^\-]+?)-(.*).rpm$#

เสร็จแล้ว! เพิ่งได้รับทั้งสองส่วนในตัวแปร$1และ$2

ความคิดเห็นเกี่ยวกับสายการบินแรก:

lsผมอยู่ในไดเรกทอรีที่มีไฟล์หลายรอบต่อนาทีจึง

perl -p เทียบเท่ากับ

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

ซึ่งอธิบายว่าฉันต้องใส่ null-string $_เพื่อหลีกเลี่ยงการพิมพ์ Perl กลับบรรทัดหลังจากที่ฉันได้แยกและกำหนดเองพิมพ์ โปรดทราบว่าฉันสามารถใช้การแทนที่เพื่อหลีกเลี่ยง 'แฮ็ค' ตัวเล็กนี้


นี้ไม่ได้ทำงานที่ทุกคนในหลายร้อยชื่อ RPM module-init-tools-3.9-21.el6_4.x86_64.rpmเช่น
Nemo

0

IMHO วิธีของเชลล์ที่ง่ายที่สุดคือ:

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 script เพื่อรับค่าและตั้งเป็นตัวแปร:

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

มันจะให้ผลลัพธ์แม้ว่าจะไม่ได้ติดตั้งแพ็คเกจก็ตาม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.