如何不依赖rpm工具编程排序含不同版本格式的文件行?
不用RPM工具实现RPM文件名版本排序的方案
当然可以!完全不需要依赖rpm工具,通过编程就能精准实现这类版本排序——核心是按照RPM的版本比较规则,正确解析文件名里的版本、发布号及特殊字段,自定义排序逻辑。下面我会分两种场景给出具体实现思路和Python代码示例。
核心思路:RPM版本比较规则
RPM文件名的标准格式是[包名]-[版本号]-[发布号].[发行标签].rpm,版本比较优先级是:
- 主版本号(比如
1.5.1里的1→5→1) - 发布号(比如
2在2_d03里) - 附加标签(比如
_d03或-k5这类特殊字段)
比较时,数字按数值大小比,非数字部分按字典序比;长度更长的版本(在前面组件相同的情况下)视为更新版本。
场景1:常规格式文件名(如cup-1.5.1-2_d03.rpm)
实现步骤
- 解析文件名,拆分出包名、版本号、发布号
- 自定义比较函数,按RPM规则逐一比较各组件
- 用比较函数对文件列表排序
Python代码示例
import re from functools import cmp_to_key def parse_rpm_filename(filename): """解析RPM文件名,返回(包名, 版本号, 发布号)""" # 去掉.rpm后缀 base = filename.rstrip('.rpm') # 从右往左拆分出发布号(第一个'-'右侧) release_split = base.rsplit('-', 1) if len(release_split) != 2: return (None, None, None) name_version_part, release = release_split # 再从右往左拆分出版本号(第一个'-'右侧) name_split = name_version_part.rsplit('-', 1) if len(name_split) != 2: return (None, None, None) package_name, version = name_split return (package_name, version, release) def rpm_component_compare(part1, part2): """比较单个版本/发布号组件,遵循RPM规则""" # 拆分数字和非数字部分(比如"1.5.1-beta"拆成['1', '.', '5', '.', '1', '-beta']) def split_component(s): return [p for p in re.split(r'(\d+)', s) if p] parts_a = split_component(part1) parts_b = split_component(part2) # 逐段比较 for p_a, p_b in zip(parts_a, parts_b): if p_a.isdigit() and p_b.isdigit(): # 数字按数值比较 num_a, num_b = int(p_a), int(p_b) if num_a != num_b: return num_a - num_b else: # 非数字按字典序比较 if p_a != p_b: return -1 if p_a < p_b else 1 # 前面组件都相同,更长的组件视为更新版本 return len(parts_a) - len(parts_b) def compare_rpm_filenames(f1, f2): """比较两个RPM文件名的版本新旧""" name1, ver1, rel1 = parse_rpm_filename(f1) name2, ver2, rel2 = parse_rpm_filename(f2) # 先比较包名(如果包名不同,按字典序排序) if name1 != name2: return -1 if name1 < name2 else 1 # 比较版本号 ver_cmp = rpm_component_compare(ver1, ver2) if ver_cmp != 0: return ver_cmp # 版本相同,比较发布号 return rpm_component_compare(rel1, rel2) # 测试常规格式文件列表 regular_rpms = [ "cup-1.4.3-3_d00.rpm", "cup-1.5.0-1_d01.rpm", "cup-1.5.1-1_d02.rpm", "cup-1.5.1-2_d03.rpm" # 最新版本 ] # 按版本从新到旧排序 sorted_regular = sorted(regular_rpms, key=cmp_to_key(compare_rpm_filenames), reverse=True) print("常规格式排序结果(最新在前):") for rpm in sorted_regular: print(f" {rpm}")
运行后会输出:
常规格式排序结果(最新在前): cup-1.5.1-2_d03.rpm cup-1.5.1-1_d02.rpm cup-1.5.0-1_d01.rpm cup-1.4.3-3_d00.rpm
场景2:含-k5这类特殊字段的文件名
假设你的特殊格式是类似cup-1.5.1-k5-2_d03.rpm(-k5作为版本修饰符)或cup-k5-1.5.1-2_d03.rpm(-k5属于包名),上面的代码依然适用——因为我们是从右往左拆分字段,不会被包名或版本中的-干扰。
如果-k5有特殊优先级(比如带-k5的版本比普通版本更高),可以在rpm_component_compare里添加特殊判断:
def rpm_component_compare(part1, part2): # 新增:优先判断-k5字段 has_k5_1 = "-k5" in part1 has_k5_2 = "-k5" in part2 if has_k5_1 != has_k5_2: return 1 if has_k5_1 else -1 # 带-k5的版本视为更新 # 原有的比较逻辑...
其他注意事项
- 如果用Python的第三方库,可以用
packaging.version.Version简化版本比较,但需要注意RPM和PEP 440规则的差异(比如RPM允许_,PEP 440用+,需要提前转换)。 - 其他编程语言(如Go、Java)也可以按同样的思路实现:解析文件名→拆分版本组件→自定义比较逻辑。
内容的提问来源于stack exchange,提问作者iamauser




