提问人:MaxU - stand with Ukraine 提问时间:10/8/2023 最后编辑:MaxU - stand with Ukraine 更新时间:10/9/2023 访问量:208
RegEx 用于解析 Fedora / Red Hat 软件包的软件包名称、软件包版本(包括发行版)
RegEx for parsing package name, package version (including release) for Fedora / Red Hat packages
问:
我的目标是正确解析 Fedora 或 Red Hat 软件包的软件包名称和软件包版本(包括发行号),如下所示:
python39-3.9.16-1.module+el8.8.0+18968+3d7b19f0.1.x86_64
python3.11-3.11.2-2.el9_2.2.aarch64
glibc-2.34-60.el9.aarch64
glib2-2.68.4-6.el9.aarch64
langpacks-core-font-en-3.0-16.el9.noarch
p11-kit-trust-0.24.1-2.el9.aarch64
tzdata-2023c-1.el9.noarch
预期结果:
pkg: python39 version: 3.9.16-1
pkg: python3.11 version: 3.11.2-2
pkg: glibc version: 2.34-60
pkg: glib2 version: 2.68.4-6
pkg: langpacks-core-font-en version: 3.0-16
pkg: p11-kit-trust: version: 0.24.1-2
pkg: tzdata version: 2023c-1
这是我的尝试:
echo -e "python39-3.9.16-1.module+el8.8.0+18968+3d7b19f0.1.x86_64\npython3.11-3.11.2-2.el9_2.2.aarch64\nglibc-2.34-60.el9.aarch64\nglib2-2.68.4-6.el9.aarch64\nlangpacks-core-font-en-3.0-16.el9.noarch\np11-kit-trust-0.24.1-2.el9.aarch64\ntzdata-2023c-1.el9.noarch" > pkgs.txt
cat pkgs.txt | sed -E 's/([^-]*)-([0-9]+(\.[0-9]+)*(-[0-9]+)?)([^0-9].*)?/pkg: \1\tversion: \2/'
我得到:
pkg: python39 version: 3.9.16-1
pkg: python3.11 version: 3.11.2-2
pkg: glibc version: 2.34-60
pkg: glib2 version: 2.68.4-6
langpacks-core-font-pkg: en version: 3.0-16
p11-kit-pkg: trust version: 0.24.1-2
pkg: tzdata version: 2023
请帮助我修复/改进正则表达式以正确解析包名称和包版本
更新我将在具有最少安装的操作系统包的容器中执行此命令(类似于 )。所以我不会安装和安装,只有一组最少的命令,如:、、、等。ubi-minimal
perl
python
cat
sed
awk
grep
答:
如果你能使用 perl :
perl -pe 's/(.*?)-([0-9].*?)\.[^0-9].*/pkg: $1\tversion: $2/' << EOF
python39-3.9.16-1.module+el8.8.0+18968+3d7b19f0.1.x86_64
python3.11-3.11.2-2.el9_2.2.aarch64
glibc-2.34-60.el9.aarch64
glib2-2.68.4-6.el9.aarch64
langpacks-core-font-en-3.0-16.el9.noarch
p11-kit-trust-0.24.1-2.el9.aarch64
tzdata-2023c-1.el9.noarch
EOF
sed
version,假设包名中没有@:
sed -E 's/\.[^0-9].*$// # Remove everything after version
s/(-[0-9].*)/@\1/ # Insert @ before version
s/([^@]+)@-(.*)/pkg: \1\tversion: \2/' << EOF
python39-3.9.16-1.module+el8.8.0+18968+3d7b19f0.1.x86_64
python3.11-3.11.2-2.el9_2.2.aarch64
glibc-2.34-60.el9.aarch64
glib2-2.68.4-6.el9.aarch64
langpacks-core-font-en-3.0-16.el9.noarch
p11-kit-trust-0.24.1-2.el9.aarch64
tzdata-2023c-1.el9.noarch
EOF
评论
perl
java-17-openjdk-17.0.6.0.10-1.fc38.x86_64
java-17-openjdk
17.0.6.0.10
1.fc38
x86_64
pkg: java-17-openjdk version: 17.0.6.0.10-1
pkg: java version: 17-openjdk-17.0.6.0.10-1
使用 RedHat 或 Fedora 提供的包管理器返回名称和版本无疑比使用正则表达式解析包名更可靠。rpm
例:
#!/bin/sh
for pkg in
python39-3.9.16-1.module+el8.8.0+18968+3d7b19f0.1.x86_64 \
python3.11-3.11.2-2.el9_2.2.aarch64 \
glibc-2.34-60.el9.aarch64 \
glib2-2.68.4-6.el9.aarch64 \
langpacks-core-font-en-3.0-16.el9.noarch \
p11-kit-trust-0.24.1-2.el9.aarch64 \
tzdata-2023c-1.el9.noarch
do
rpm -qp --queryformat 'pkg: %{NAME} version: %{VERSION}' "$pkg.rpm"
done
或者,如果具有所有文件名,则甚至不需要循环:.rpm
rpm -qp --queryformat 'pkg: %{NAME} version: %{VERSION}' \
python39-3.9.16-1.module+el8.8.0+18968+3d7b19f0.1.x86_64.rpm \
python3.11-3.11.2-2.el9_2.2.aarch64.rpm \
glibc-2.34-60.el9.aarch64.rpm \
glib2-2.68.4-6.el9.aarch64.rpm \
langpacks-core-font-en-3.0-16.el9.noarch.rpm \
p11-kit-trust-0.24.1-2.el9.aarch64.rpm \
tzdata-2023c-1.el9.noarch.rpm
对于您显示的示例,请尝试遵循Perl单行解决方案。在此处使用正则表达式,它创建了 2 个捕获组,我们使用它们来打印值,同时根据所需的输出在此处执行替换。^(.*?)-([0-9]+[a-zA-Z]*(?:\.[0-9]+)*(?:-[a-zA-Z0-9]+)?)
perl -pe 's/^(.*?)-([0-9]+[a-zA-Z]*(?:\.[0-9]+)*(?:-[a-zA-Z0-9]+)?)/pkg: $1\tversion: $2/' Input_file
评论
awk
如果你的容器有这个命令,那么它提供了最安全的方式来执行你想要的操作(如至少一个其他答案中所述)。rpm
如果您没有该命令,那么您可以根据 RPM 文件格式中所述的 RPM 包命名标准,相当轻松安全地执行您想要执行的操作。格式为 (NVRA)。由于内部连字符(破折号、字符)只能出现在 中,而 从不包含点,因此将包名称解析为其部分非常简单。rpm
name-version-release.architecture
-
name
architecture
便携式(无)解决方案是:-E
sed
sed 's/\(.*\)-\(.*-[^.]*\).*/pkg: \1 version: \2/' pkgs.txt
也可以通过标准的 shell 字符串操作来完成。我(轻轻地)用和测试了这个 Shellcheck-clean 代码:bash
dash
#! /bin/sh -
while read -r nvra || [ -n "$nvra" ]; do
nv=${nvra%-*}
ra=${nvra##*-}
n=${nv%-*}
v=${nv##*-}
printf 'pkg: %s version: %s-%s\n' "$n" "$v" "${ra%%.*}"
done <pkgs.txt
不过,如果文件很大(我猜超过 1000 行),纯 shell 代码会明显变慢。pkgs.txt
在这里添加一个答案,因为 OP 说可能不在他们的容器中。这里使用了GNU。awk
perl
awk
- 根据所示样品制作字段分隔符。
(\\+|\\.)el[0-9]+(\\.[0-9]*)*
- 然后使用函数匹配正则表达式来获取此处的版本值。
match
-([0-9]+[a-zA-Z]*)([^-]+)(-[a-zA-Z0-9]+)?
- 然后再次使用函数在版本之前获取值,如果支持延迟匹配:)会更容易做到
match
awk
awk -F'(\\+|\\.)el[0-9]+(\\.[0-9]*)*' '
match($1,/-([0-9]+[a-zA-Z]*)([^-]+)(-[a-zA-Z0-9]+)?/,arr){
val=arr[1] arr[2] arr[3]
}
match($1,val){
print "pkg: " substr($1,1,RSTART-2) "\tversion: " val
}
' Input_file
或者使用一个后的命令来获得好看格式的输出。column
awk
awk -F'(\\+|\\.)el[0-9]+(\\.[0-9]*)*' '
match($1,/-([0-9]+[a-zA-Z]*)([^-]+)(-[a-zA-Z0-9]+)?/,arr){
val=arr[1] arr[2] arr[3]
}
match($1,val){
print "pkg: " substr($1,1,RSTART-2) "\tversion: " val
}
' Input_file | column -t
评论
rpm
rpm -qp --queryformat '%{VERSION}' package.rpm
2023c-1
(-[0-9]+)
s/([^-]*)-([0-9][^-]*-[0-9]*).*/
sed
sed -E 's/\.[^0-9].*//; s/-([0-9].*)/ version: \1/; s/^/pkg: /'