含非拉丁字符的sort命令列排序异常问题及解决
问题描述
场景1:无分隔符文件排序正常
第一个文件input1.txt内容:
γβα αγβ βαγ
执行命令:
sort -t'|' -f -i path/to/input1.txt > path/to/output1.txt
得到符合预期的排序结果:
αγβ βαγ γβα
场景2:指定排序键后排序异常
第二个文件input2.txt内容:
1|γβα 2|αγβ 3|βαγ
想要按第二列的希腊字母顺序排序,执行命令:
sort -t'|' -f -i -k2 path/to/input2.txt > path/to/output2.txt
但输出结果完全不符合预期:
1|γβα 2|αγβ 3|βαγ
预期输出应该是:
2|αγβ 3|βαγ 1|γβα
环境信息
初始locale配置:
LANG=C.UTF-8 LC_CTYPE="C.UTF-8" LC_NUMERIC="C.UTF-8" LC_TIME="C.UTF-8" LC_COLLATE="C.UTF-8" LC_MONETARY="C.UTF-8" LC_MESSAGES="C.UTF-8" LC_ALL=
将LANG="en_US.utf8"添加到.bash_profile并导出后,更新后的locale:
LANG=en_US.utf8 LC_CTYPE="en_US.utf8" LC_NUMERIC="en_US.utf8" LC_TIME="en_US.utf8" LC_COLLATE="en_US.utf8" LC_MONETARY="en_US.utf8" LC_MESSAGES="en_US.utf8" LC_ALL=
执行file -bi path/to/input2.txt确认文件编码为:text/plain; charset=utf-8,重新执行排序命令后结果仍异常。
疑问
- 为什么指定排序键的命令不起作用?
- 怎么对包含非拉丁字符的列进行字母排序?
- 为什么不指定排序键时排序结果是正常的?
问题解答
1. 指定排序键无效的核心原因
问题根源是**-i选项的副作用**:
-i选项的作用是忽略非打印字符,但在C.UTF-8或en_US.utf8locale下,希腊字母的UTF-8编码字节超出了ASCII打印字符范围,会被-i判定为非打印字符而忽略。这样第二列的希腊字母全部被过滤为空字符串,所有行的排序键都相同。- 当
sort发现指定排序键一致时,会自动回退到按整行排序,而你的整行开头是数字1、2、3,所以最终输出按数字顺序排列,也就是你看到的异常结果。 - 补充:
-k2的写法是从第二列开始到行尾作为排序键,更严谨的写法是-k2,2(仅指定第二列),但这不是本次问题的核心原因。
2. 针对非拉丁字符列的正确排序方法
按以下调整即可解决:
- 移除
-i选项:希腊字母是你要排序的目标字符,-i会过滤掉这些有效内容,完全没必要保留。 - 明确指定排序键范围:用
-k2,2代替-k2,确保仅以第二列作为排序依据,避免意外包含其他内容。 - 匹配合适的locale:
- 用
C.UTF-8locale即可,它按Unicode代码点排序,希腊字母α、β、γ的代码点顺序刚好符合自然字母顺序。 - 若要严格遵循希腊语排序规则,可使用
el_GR.utf8locale(需确保系统已安装,可用locale -a查看)。
- 用
最终正确命令示例:
# 使用C.UTF-8 locale排序 LC_COLLATE=C.UTF-8 sort -t'|' -f -k2,2 path/to/input2.txt > path/to/output2.txt # 或者使用希腊语locale(系统支持的话) LC_COLLATE=el_GR.utf8 sort -t'|' -f -k2,2 path/to/input2.txt > path/to/output2.txt
3. 不指定排序键时排序正常的原因
当不指定-k选项时,sort会把整行当作完整排序键:
- 第一个文件里没有
|分隔符,-t'|'不生效,整行的希腊字母直接作为排序键。此时-i选项虽然存在,但C.UTF-8locale下希腊字母被识别为打印字符,不会被忽略,所以sort按Unicode代码点顺序排序,得到符合预期的结果。 - 要是用第二个文件不指定
-k,sort会按整行排序,结果会是数字1、2、3的顺序,只是第一个文件的场景刚好适配,才出现了“正常”的排序结果。
内容的提问来源于stack exchange,提问作者lyrically wicked
相关产品推荐
相关产品推荐

