Unix对下划线字符的排序处理

31

我有两台linux机器,在这些机器上unix sort命令似乎表现不同。我相信我已经把问题缩小到下划线字符的处理方式上。

如果我运行sort tmp,其中tmp包含以下两行:

aa_d_hh
aa_dh_ey

一台机器输出

aa_d_hh
aa_dh_ey
(即 '_' 在 'h' 之前) 而其他输出
aa_dh_ey
aa_d_hh
(即'h'在'_'之前)。 我需要这些机器一起工作(因为我稍后会使用sort -m,合并非常大的文件)。 是否有任何方法可以强制sort按照一种或另一种方式工作? 谢谢。

在两台机器上尝试运行 "sort --version" 命令,它们是否相同? - sud03r
5个回答

41

你可以仅针对你的命令将LC_COLLATE设置为传统排序:

env LC_COLLATE=C sort tmp

这不会改变当前环境,只会影响sort命令执行的环境。 使用这个命令应该会得到相同的结果。


1
还有哪些有效的 LC_COLLATE 选择?假设我特别想把下划线移到底部,应该使用什么值? - Steve Pitchers
LC_COLLATE=en_US.ASCII 是另一个有效的选择,它对下划线的排序方式与 C 相同。 - Dan Lenski

8

这很可能是由于区域设置不同造成的。在 en_US.UTF-8 区域设置中,下划线 (_) 排在字母和数字之后,而在POSIX C 区域设置 中,它们会在大写字母和数字之后,但在小写字母之前。

# won't change LC_COLLATE=C after execution
$ LC_COLLATE=C sort filename

您还可以使用sort --debug来显示有关排序行为的更多信息:

$ (echo 'foo_bar'; echo 'fooAbar'; echo 'foo0bar'; echo 'fooabar') |
      LC_COLLATE=en_US.UTF-8 sort --debug
sort: using ‘en_US.UTF-8’ sorting rules
foo0bar
fooabar
fooAbar
foo_bar

$ (echo 'foo_bar'; echo 'fooAbar'; echo 'foo0bar'; echo 'fooabar') | 
      LC_COLLATE=C sort --debug
sort: using simple byte comparison
foo0bar
fooAbar
foo_bar
fooabar

此回答所示,您可以使用上述公式在不修改shell环境的情况下强制对单个命令使用LC_COLLATE=C


1
“小写数字” - 我猜你想说的是“小写字母” :) - bers
谢谢@bers,已修复! - Dan Lenski

4

我非常喜欢上面有用例子的答案,但我会再添加一个字符串到列表中以展示排序行为的奇怪之处:

$ (echo 'foo_bar'; echo 'fooAbar'; echo 'foo0bar'; echo 'fooabar'; echo 'foobbar'; echo 'foobar') | LC_COLLATE=en_US.UTF-8 sort --debug
sort: using ‘en_US.UTF-8’ sorting rules
foo0bar
_______
fooabar
_______
fooAbar
_______
foobar
______
foo_bar
_______
foobbar
_______

听起来很疯狂,对吧?这里找到了解释,实际上是因为在此区域设置中使用了Unicode排序算法: https://unix.stackexchange.com/questions/252419/unexpected-sort-order-in-en-us-utf-8-locale

然而,即使使用“sort --debug”选项,也不能轻易地演示 strcoll() 函数遵守区域设置排序规范的细微差别。

POSIX 规定,区域设置的作者(除C语言区域设置外)对 strcoll() 的行为的所有琐碎方面都有绝对控制权,而两个供应商宣称其区域设置命名为en_US.UTF-8并不意味着/要求这两个供应商具有相同的区域设置定义。 因此,两个不同平台之间的排序规则很可能不同,取决于编写该平台的区域设置文件的人以及随时间推移所纳入的区域设置定义修复。

感谢红帽公司的Eric Blake提供此见解。


3
使用 sort -V 解决了我的问题。正如 sort --help 所说:-V, --version-sort natural sort of (version) numbers within text,它可以处理下划线并将其放置在末尾。 - allenyllee

4

排序顺序取决于当前环境变量LC_COLLATE的值。请查看本地文档以了解有关“locale”、“setlocale”等的信息。在两台机器上都将LC_COLLATE设置为“POSIX”,结果应该是相同的。


我的电脑上没有这样的环境变量,但是排序功能正常。 - sud03r

0

这种差异是由于您的语言环境造成的。使用locale命令检查当前设置。

有许多不同的语言环境类别,例如LC_COLLATELC_TIMELC_MESSAGES。您可以通过设置环境变量LC_ALLLANG来更改它们所有,或者只通过设置环境变量LC_COLLATE来更改排序顺序。语言环境CPOSIX是标准定义的基本语言环境;其他语言环境包括en_US(美式英语)、fr_FR(法语)等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接