![为什么 Gnu sort 在我的 OSX 机器和 Linux 机器上的排序不同?](https://linux22.com/image/110752/%E4%B8%BA%E4%BB%80%E4%B9%88%20Gnu%20sort%20%E5%9C%A8%E6%88%91%E7%9A%84%20OSX%20%E6%9C%BA%E5%99%A8%E5%92%8C%20Linux%20%E6%9C%BA%E5%99%A8%E4%B8%8A%E7%9A%84%E6%8E%92%E5%BA%8F%E4%B8%8D%E5%90%8C%EF%BC%9F.png)
sort
我有一台从 coreutils 8.26运行 GNU sort
(从 Homebrew 安装)的 OSX 机器,以及一台从 coreutils 8.25sort
运行 GNU的 Linux 机器。sort
在 Mac 上:
mac$ echo -e "{1\n2" | sort
2
{1
在 Linux 上时:
linux$ echo -e "{1\n2" | sort
{1
2
我知道这sort
取决于语言环境。我locale
在 Linux 机器上运行,在每行输出前面加上 ,export
并在 OSX 机器上运行结果行,然后再次运行(在同一终端中)排序命令,这给出了与之前相同的输出。
然而,我注意到,locale
在 Mac 上运行并没有显示 Linux 上出现的所有行,我不确定这是否相关。
Linux 上的语言环境:
linux$ locale
LANG=en_CA.UTF-8
LANGUAGE=en_CA:en
LC_CTYPE="en_CA.UTF-8"
LC_NUMERIC="en_CA.UTF-8"
LC_TIME="en_CA.UTF-8"
LC_COLLATE="en_CA.UTF-8"
LC_MONETARY="en_CA.UTF-8"
LC_MESSAGES="en_CA.UTF-8"
LC_PAPER="en_CA.UTF-8"
LC_NAME="en_CA.UTF-8"
LC_ADDRESS="en_CA.UTF-8"
LC_TELEPHONE="en_CA.UTF-8"
LC_MEASUREMENT="en_CA.UTF-8"
LC_IDENTIFICATION="en_CA.UTF-8"
LC_ALL=en_CA.UTF-8
OSX 上的语言环境:
mac$ locale
LANG="en_CA.UTF-8"
LC_COLLATE="en_CA.UTF-8"
LC_CTYPE="en_CA.UTF-8"
LC_MESSAGES="en_CA.UTF-8"
LC_MONETARY="en_CA.UTF-8"
LC_NUMERIC="en_CA.UTF-8"
LC_TIME="en_CA.UTF-8"
LC_ALL="en_CA.UTF-8"
我发现如果我LC_ALL=C
在两台机器上设置,它们都会排序2
before {1
。但如果我LC_ALL=en_CA.UTF-8
在两台机器上设置,我会得到如上所述的不同输出。如果我LC_ALL=en_CA.utf8
在两台机器上设置也是一样。 (在 Linux 计算机上locale -a
列出,但在 OSX 计算机上列出。)en_CA.utf8
en_CA.UTF-8
知道这是怎么回事吗?
答案1
前几天我对同样的问题做了一些挖掘,所以让我分享一个技术答案。
在 macOS 上,/usr/share/locale/en_US.UTF-8/LC_COLLATE
(或en_CA.UTF-8
,同样的东西)是 的符号链接/usr/share/locale/la_LN.US-ASCII/LC_COLLATE
,它是从la_LN.US-ASCII.src
和colldef
。以下是全文la_LN.US-ASCII.src
:
# ASCII
#
# $FreeBSD: src/share/colldef/la_LN.US-ASCII.src,v 1.2 1999/08/28 00:59:47 peter Exp $
#
order \
\x00;...;\xff
您可以通过验证校验和来验证二进制LC_COLLATE
文件是否确实是从中生成的la_LN.US-ASCII.src
:
$ colldef -o /dev/stdout usr-share-locale.tproj/colldef/la_LN.US-ASCII.src | sha256sum
9ec9b40c837860a43eb3435d7a9cc8235e66a1a72463d11e7f750500cabb5b78 -
$ sha256sum </usr/share/locale/en_US.UTF-8/LC_COLLATE
9ec9b40c837860a43eb3435d7a9cc8235e66a1a72463d11e7f750500cabb5b78 -
该规则集很容易理解:只需将字节值一一比较即可。因此,排序规则en_US.UTF-8
与 POSIX 语言环境(又名 C 语言环境)相同。{
是 0x7B,2
是 0x32,所以{
在 后面2
。
该规则集是 FreeBSD 5 的产物,已同步到 Mac OS X 10.3 Panther 中。看colldef
FreeBSD 5.0.0 源代码树中的目录。从那时起,它在 OS X / macOS 上就再也没有改变过。
在 Linux 上,区域设置程序和数据是glibc
.参见 glibclocaledata/locales
树,或/usr/share/i18n/locales
在 Debian/Ubuntu 上。如果您检查/usr/share/i18n/locales/en_US
,您会发现它iso14651_t1_common
符合LC_COLLATE
规则。所以如下ISO 14651整理规则。
博客文章中有更多详细信息:https://blog.zhimingwang.org/macos-lc_collate-hunt。