给定一个名为 txt
的文件:
ab
a c
a a
调用 sort txt
后,我获得:
a a
ab
a c
换句话说,这不是正确的排序,它会删除/忽略空格!我原本期望这是sort -i
的行为,但它发生在有或没有-i
标志的情况下。我想要得到“正确”的排序。
a a
a c
ab
我该如何做到这一点?
给定一个名为 txt
的文件:
ab
a c
a a
调用 sort txt
后,我获得:
a a
ab
a c
换句话说,这不是正确的排序,它会删除/忽略空格!我原本期望这是sort -i
的行为,但它发生在有或没有-i
标志的情况下。a a
a c
ab
我该如何做到这一点?
解决者:
export LC_ALL=C
警告:环境指定的语言环境会影响排序顺序。设置 LC_ALL=C 以获得使用本机字节值的传统排序顺序。
(至少适用于ASCII,对于UTF8无法确定)
sort
的帮助菜单上写着:
*** 警告 ***
环境指定的语言环境会影响排序顺序。
设置LC_ALL=C以获取使用本地字节值的传统排序顺序。 - A. K.LC_ALL=C
破坏了我的 UTF8 字符显示...所以要么我无法正确排序它们,要么无法正确显示它们。太好了! - dagneliesLC_ALL=C sort ...
一样。 - CmdrMoozy如前所述,LC_ALL=C sort
就可以解决问题。这是因为不同的语言对于排序字符有不同的规则,这些规则通常由高级语言学家而非计算机科学专家制定。而你所在的区域设置中,这些规则似乎认为在排序中应该忽略空格。
通过在 LC_ALL 前加上 C(或者当 LC_ALL 未设置时,LC_COLLATE=C
也可以),你明确地声明了无关语言的排序方式(以及数字格式和其他东西)。这正是你在这种情况下所需要的。如果你想将这个设置作为默认值,在你的环境中导出 LC_COLLATE 即可。
选择这种默认方式是为了保持与“正常”的现实世界排序方案(例如电话簿)的一致性,这些方案通常会忽略空格。
sort_posix() { env LC_COLLATE=POSIX sort "$@"; }
。 - myrdd在一些语言中,有些字母超出了[A-Za-z]的范围,因此仅使用C语言环境即按照字节值排序并不是一个好的解决方案。这些字母在UTF-8中由多个字节表示,因此字节值的排序顺序并不是我们想要的。(有些字符可能有两种等效的表示形式(预组合和分解))。
尽管如此,空格的处理仍然是一个问题。 我尝试了以下方法:
$ cat stest
a b
a c
ab
a d
$ sort stest
ab
a b
a c
a d
$ sort -k 1,1 stest
a b
a c
a d
ab
对于我的需求,使用“-k 1,1”就可以解决问题了。我尝试过另一种但比较麻烦的解决方案,即将空格替换为某个辅助字符,然后进行排序,最后再将辅助字符改回空格。
我一直在研究如何优化我维护的一个shell脚本,因为它有很多国际用户(重点是百分比,而不是数量)。
我在网上和SO上看到的大多数选项似乎都建议像这里看到的那样,在全局范围内设置区域设置(过度)。
export LC_ALL=C
或者像从gnu.org这样将其输送到每个单独的命令中(繁琐)
$ echo abcdefghijklmnopqrstuvwxyz | LC_ALL=C /usr/xpg4/bin/tr 'a-z' 'A-Z' ABCDEFGHIJKLMNOPQRSTUVWXYZ
#!/bin/bash
# locale_checker.sh
#Check and set locale to LC_ALL to optimize character sort and search.
echo "locale was $LANG"
LANG=C
locale
并输出证明它是临时的,并且可以限制为我的脚本进程的内容。
mateor@:~/snippets$ ./locale_checker.sh
locale was en_US.UTF-8
LANG=C
LANGUAGE=en_US:en
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=
mateor@:~/snippets$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
这样做可以获得优化的区域设置,而不会破坏其他人的环境,并避免在你认为可能有帮助的地方到处传输它的乏味。
很奇怪,在这里可以运行(cygwin)。
尝试使用sort -d txt
。
对我来说
$ cat txt
ab
a c
a a
$ sort txt
a a
a c
ab
我敢打赌,在你的a
和c
之间,你有一个不间断空格、半个空格或其他高代码点空格!
编辑
刚在Linux上运行了一下。我应该看看标签。是的,我得到了与你相同的输出!我的第一次运行是在Mac上。看起来是GNU和BSD之间的差异。我会进一步调查。
编辑2:
Linux使用基于字段的排序...仍在寻找如何抑制它。尝试过了
sort -t, txt
希望欺骗GNU以为整行是一个字段,但它仍然使用当前语言环境进行排序。
编辑3:
原帖作者通过设置语言环境为C来解决了这个问题。
export LC_ALL=C
似乎没有其他方法。 sort
命令将使用当前语言环境,尽管它经常说 C
(或其别名 POSIX
)是默认语言环境,但如果您使用的是 Linux,则可能已为您设置。 输入 locale -a
查看可用的语言环境。 在我的系统上:
$ locale -a
C
POSIX
en_AG
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_NG
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZW.utf8
看起来将区域设置为 C(或其别名 POSIX)是打破基于字段的 sort
行为并将整行作为一个字段处理的唯一方法。在我看来,这相当奇怪。我认为-t
或 -k
选项,或者可能是一些新选项会是更明智的方法来实现这一点。
顺便说一句,看起来这个问题之前已经在 SO 上问过了:从 GNU sort 中得到意外结果。