为什么 Gnu sort 在我的 OSX 机器和 Linux 机器上的排序不同?

为什么 Gnu sort 在我的 OSX 机器和 Linux 机器上的排序不同?

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在两台机器上设置,它们都会排序2before {1。但如果我LC_ALL=en_CA.UTF-8在两台机器上设置,我会得到如上所述的不同输出。如果我LC_ALL=en_CA.utf8在两台机器上设置也是一样。 (在 Linux 计算机上locale -a列出,但在 OSX 计算机上列出。)en_CA.utf8en_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.srccolldef。以下是全文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 中。看colldefFreeBSD 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_collat​​e-hunt

相关内容