You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何不依赖rpm工具编程排序含不同版本格式的文件行?

不用RPM工具实现RPM文件名版本排序的方案

当然可以!完全不需要依赖rpm工具,通过编程就能精准实现这类版本排序——核心是按照RPM的版本比较规则,正确解析文件名里的版本、发布号及特殊字段,自定义排序逻辑。下面我会分两种场景给出具体实现思路和Python代码示例。

核心思路:RPM版本比较规则

RPM文件名的标准格式是[包名]-[版本号]-[发布号].[发行标签].rpm,版本比较优先级是:

  1. 主版本号(比如1.5.1里的151
  2. 发布号(比如22_d03里)
  3. 附加标签(比如_d03-k5这类特殊字段)

比较时,数字按数值大小比,非数字部分按字典序比;长度更长的版本(在前面组件相同的情况下)视为更新版本。


场景1:常规格式文件名(如cup-1.5.1-2_d03.rpm

实现步骤

  1. 解析文件名,拆分出包名、版本号、发布号
  2. 自定义比较函数,按RPM规则逐一比较各组件
  3. 用比较函数对文件列表排序

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

火山引擎 最新活动