我有一个文件,其中包含操作系统软件包及其发行版本的列表。我只需要包名称,不需要发布版本。
如何使用 Linux 命令或任何脚本来实现此目的?
例子:
bind-export-libs-9.11.4-26.P2.el7_9.13
bind-export-libs-9.11.4-26.P2.el7_9.7
bind-libs-9.11.4-16.P2.el7
bind-libs-9.11.4-16.P2.el7_8.6
atk-2.28.1-1.el7
atk-2.28.1-2.el7
at-spi2-atk-2.26.2-1.el7
at-spi2-core-2.28.0-1.el7
在上面的列表中,根据发行版本存在重复的包条目。
如何只提取包名称?
答案1
我几乎确定您的列表是由rpm -qa
类似的东西生成的,因此我给您一个命令,该命令仅显示包名称而不显示版本。这可以节省以后的大量工作:
rpm -qa --queryformat '%{NAME}\n' | sort
答案2
只需从倒数第二个破折号开始修剪所有内容即可。
使用sed
:
sed -r 's/-[^-]+-[^-]+$//' file.txt
基本上,RPM NVR 的通用格式是<name_possibly_containing_embedded_dashes_or_digits>-<version_never_containing_dashes>-<release_never_containing_dashes>
.点或数字没有任何特殊含义,因此搜索它们永远无法正常进行。
在 的输出上运行它rpm -qa
应该产生与 完全相同的列表rpm -qa --queryformat '%{NAME}\n'
,如建议的那样Artem 的回答。请注意,如果安装了单个软件包的多个版本或发行版,仍然会有重复的条目(前者是内核软件包或 gpg-pubkeys 的规范,后者是 i686/x86_64 库的典型)。sort -u
如果您确实只想要唯一名称的列表,请运行结果。
# these two should produce the same output:
rpm -qa | sed -r 's/-[^-]+-[^-]+$//'
rpm -qa --queryformat '%{NAME}\n'
答案3
我觉得是TooTea的回答指出了正确的方法,而不是这个,出于参考原因,我仍然会保留它。
长话短说:RPM 文件名约定很复杂,并且如下所示,并不唯一。因此,在某些情况下,您实际上无法知道正确的包名称和版本控制是什么。不过,你可以尝试一下。
然而,由于这很复杂,所以不能简单地用 和 正则表达式来完成sed
。不适合这项工作的工具。相反,使用 Redhat/Fedora 自己的工具。这个 Python 脚本应该会给你你想要的:
#!/usr/bin/env python3
from dnf.subject import Subject
from sys import stdin
from typing import Set
import hawkey
def filename_to_name_candidates(filename: str) -> Set[str]:
subj = Subject(filename)
return {
candidate.name
for candidate in subj.get_nevra_possibilities(forms=hawkey.FORM_NEVRA)
}
names = set()
for line in stdin:
try:
names = names | filename_to_name_candidates(line)
except:
pass
for name in sorted(names):
print(name)
将其保存在某处(例如,作为filename2packagename
),使其可执行,(chmod 755 filename2packagename
)。然后您可以通过管道输入文件名:
./filename2packagename < listofnames.txt
答案4
使用sed
$ sed -En 's/([^.]*)-.*/\1/;G;/^(.*)\n.*\n\1/d;H;P' input_file
bind-export-libs
bind-libs
atk
at-spi2-atk
at-spi2-core