如何按版本号对Apache软件版本记录文件进行排序?
嘿,我来帮你解决这个版本号排序的问题!你之前用awk没得到正确结果,大概率是因为直接按字符串排序了——版本号的数字段按字符串比和按实际语义比结果完全不一样,比如0.10.0字符串排序会排在0.2.0前面,但实际版本号它明明更大对吧?
下面给你几个靠谱的解决方案,从简单到灵活都有:
sort的版本排序选项(最省心) GNU sort自带一个-V(或者--version-sort)选项,专门用来处理这种带点分隔的版本号序列,直接就能按语义正确排序,不用自己折腾提取字段。
假设你的Test.txt内容是:
File: Test.txt
org.apache.hive.v.0.3.5
org.apache.pig.v.0.2.3
org.apache.hadoop.0.1.1
org.apache.v.0.2.5
如果不需要保留第一行的文件说明,直接跳过它再排序:
tail -n +2 Test.txt | sort -V
输出结果会是:
org.apache.hadoop.0.1.1 org.apache.pig.v.0.2.3 org.apache.v.0.2.5 org.apache.hive.v.0.3.5
要是想保留第一行,就先输出该行,再处理后面的内容:
head -n 1 Test.txt && tail -n +2 Test.txt | sort -V
如果你的系统里的sort没有-V选项(比如某些BSD系统),可以用awk先把版本号拆成数字段,生成一个能正确排序的“键”,再配合sort处理。
比如我们假设所有版本号都是x.y.z格式,提取每个条目最后三个数字段,把每个数字补成两位(比如0.1.1变成01.02.03),这样字符串排序就和语义排序一致了:
awk 'NR>1 { split($0, parts, /\./); # 取最后三个部分作为版本号的x、y、z段 v1 = parts[length(parts)-2]; v2 = parts[length(parts)-1]; v3 = parts[length(parts)]; # 生成补零后的排序键 key = sprintf("%02d.%02d.%02d", v1, v2, v3); print key "\t" $0 } NR==1 {print $0}' Test.txt | sort -k1,1 | awk 'NR==1 {print $0} NR>1 {print $2}'
这个命令的逻辑是:
- 第一行直接输出
- 从第二行开始,拆分条目提取版本号,生成补零的排序键
- 把键和原内容一起输出,按键排序后,再去掉键输出原内容
如果不想依赖sort,也可以在awk里把所有条目存起来,自定义排序逻辑:
# 读取文件,第一行存为表头,其余行存入数组 NR==1 {header = $0; next} { split($0, parts, /\./); # 把版本号转换成整数(比如0.1.1 → 101,0.2.3 → 203),方便排序 version_num = parts[length(parts)-2] * 10000 + parts[length(parts)-1] * 100 + parts[length(parts)]; lines[NR-1] = $0; versions[NR-1] = version_num; } END { print header; # 冒泡排序,按版本号的整数大小排序 for(i=1; i<=length(lines); i++) { for(j=i+1; j<=length(lines); j++) { if(versions[i] > versions[j]) { # 交换版本号和对应行 tmp_v = versions[i]; versions[i] = versions[j]; versions[j] = tmp_v; tmp_l = lines[i]; lines[i] = lines[j]; lines[j] = tmp_l; } } } # 输出排序后的行 for(k=1; k<=length(lines); k++) { print lines[k]; } }
把上面的代码存成sort_version.awk,然后运行:
awk -f sort_version.awk Test.txt
这个方法是把版本号转换成一个整数,通过比较整数大小来保证排序的语义正确性。
内容的提问来源于stack exchange,提问作者z_1_p

