Linux Bash:按特殊字符优先排序指定子串的实现方案
问题
我需要对输入文件按第8个“/”后的子串(即“svc...”开头的部分)排序,且该子串内需按以下优先级排序:1. 字符“:”,2. 字符“/”,3. 字母字符。请问如何用sort命令或其他方法实现?
输入文件:
/path1/path2/path3/path4/path5/path6/ser/svcba/log: /path1/path2/path3/path4/path5/path6/ser/svcba: /path1/path2/path3/path4/path5/path6/ser/svcbb/log: /path1/path2/path3/path4/path5/path6/ser/svcbc/log: /path1/path2/path3/path4/path5/path6/ser/svcbc: /path1/path2/path3/path4/path5/path6/ser/svcb/log: /path1/path2/path3/path4/path5/path6/ser/svcb: /path1/path2/path3/path4/path5/path6/ser/svca/log: /path1/path2/path3/path4/path5/path6/ser/svca: /path1/path2/path3/path4/path5/path6/ser/svcbb:
期望输出:
/path1/path2/path3/path4/path5/path6/ser/svca: /path1/path2/path3/path4/path5/path6/ser/svca/log: /path1/path2/path3/path4/path5/path6/ser/svcb: /path1/path2/path3/path4/path5/path6/ser/svcb/log: /path1/path2/path3/path4/path5/path6/ser/svcba: /path1/path2/path3/path4/path5/path6/ser/svcba/log: /path1/path2/path3/path4/path5/path6/ser/svcbb: /path1/path2/path3/path4/path5/path6/ser/svcbb/log: /path1/path2/path3/path4/path5/path6/ser/svcbc: /path1/path2/path3/path4/path5/path6/ser/svcbc/log:
已尝试但未达预期的命令:
# 直接sort,带/log的行排在不带的前面,不符合需求 cat input.txt | sort /path1/path2/path3/path4/path5/path6/ser/svca/log: /path1/path2/path3/path4/path5/path6/ser/svca: /path1/path2/path3/path4/path5/path6/ser/svcba/log: /path1/path2/path3/path4/path5/path6/ser/svcba: /path1/path2/path3/path4/path5/path6/ser/svcbb/log: /path1/path2/path3/path4/path5/path6/ser/svcbb: /path1/path2/path3/path4/path5/path6/ser/svcbc/log: /path1/path2/path3/path4/path5/path6/ser/svcbc: /path1/path2/path3/path4/path5/path6/ser/svcb/log: /path1/path2/path3/path4/path5/path6/ser/svcb: # 以:为分隔符排序,svcb/log的位置错误 cat input.txt | sort -t : -k 1,1 /path1/path2/path3/path4/path5/path6/ser/svca: /path1/path2/path3/path4/path5/path6/ser/svca/log: /path1/path2/path3/path4/path5/path6/ser/svcb: /path1/path2/path3/path4/path5/path6/ser/svcba: /path1/path2/path3/path4/path5/path6/ser/svcba/log: /path1/path2/path3/path4/path5/path6/ser/svcbb: /path1/path2/path3/path4/path5/path6/ser/svcbb/log: /path1/path2/path3/path4/path5/path6/ser/svcbc: /path1/path2/path3/path4/path5/path6/ser/svcbc/log: /path1/path2/path3/path4/path5/path6/ser/svcb/log: # 以/为分隔符取第9段排序,带/log的行仍排在前面 cat input.txt | sort -t / -k 9,9 /path1/path2/path3/path4/path5/path6/ser/svca/log: /path1/path2/path3/path4/path5/path6/ser/svca: /path1/path2/path3/path4/path5/path6/ser/svcb/log: /path1/path2/path3/path4/path5/path6/ser/svcba/log: /path1/path2/path3/path4/path5/path6/ser/svcba: /path1/path2/path3/path4/path5/path6/ser/svcbb/log: /path1/path2/path3/path4/path5/path6/ser/svcbb: /path1/path2/path3/path4/path5/path6/ser/svcbc/log: /path1/path2/path3/path4/path5/path6/ser/svcbc: /path1/path2/path3/path4/path5/path6/ser/svcb:
解决方案
可以通过awk预处理生成自定义排序键,再结合sort实现需求,具体命令如下:
awk -F '/' '{key=$9; gsub(/:/, "\x01", key); gsub(/\//, "\x02", key); print key "\t" $0}' input.txt | sort | cut -f2-
命令解释:
awk部分:
-F '/':以/作为字段分隔符,第8个/后的内容对应第9个字段$9gsub(/:/, "\x01", key):把排序键中的:替换成ASCII值为1的控制字符(该字符比/和所有字母的ASCII值都小,排序时会排在最前)gsub(/\//, "\x02", key):把排序键中的/替换成ASCII值为2的控制字符(比字母小,比\x01大,排序时排在:之后、字母之前)print key "\t" $0:将自定义排序键和原行内容用制表符分隔输出
sort:对awk输出的内容按排序键进行字典序排序,此时
:对应的\x01会优先于/对应的\x02,最后是字母cut -f2-:去掉前面的自定义排序键,只保留原行内容,得到最终的排序结果
执行该命令后,输出将与你期望的结果完全一致。
内容的提问来源于Stack Exchange,提问作者wasilis
相关产品推荐
相关产品推荐

