UNIXsorting忽略空格

这是一个简单的问题。

给定一个文件txt

 ab ac aa 

当调用sort txt ,我得到:

 aa ab ac 

换句话说,这是不正确的sorting,这种删除/忽略空格! 我期望这是sort -i的行为,但它发生有或没有-i标志。

我想获得“正确的”sorting:

 aa ac ab 

我该怎么做?

解决:

export LC_ALL=C

…不知道为什么。

(至少对ASCII工作,不知道UTF8)

就像之前提到的, LC_ALL=C sort就是诀窍。 这是因为不同的语言对字符排序有不同的规则,这些规则往往是由高级语言学家而不是CS专家制定的。 而就这些规则而言,就你的语言环境而言,似乎认为空间在排序时应该被忽略。

通过给LC_ALL = C加上前缀(或者当LC_ALL未被设置时, LC_COLLATE=C就足够了),你明确地声明了语言不可知的排序(以及LC_ALL,数字格式和东西),这就是你想要的。 如果您想将其设置为默认值,请在您的环境中导出LC_COLLATE。

默认值是这样选择的,以保持与“正常的”真实世界的排序方案(如白页)的一致性,这往往忽略空间。

使用C语言环境(即按字节值排序)在某些字母超出范围[A-Za-z]的语言中不是一个好的解决方案。 这样的字母在UTF-8中被表示为多个字节,然后字节值整理顺序不是所期望的。 (某些字符可能有两个等同的表示(预先组合和分解))。

不过,空间的处理是一个问题。 我尝试了以下内容:

 $ cat stest abac ab ad $ sort stest ab abacad $ sort -k 1,1 stest abacad ab 

为了我的需要,-k 1,1诀窍。 我尝试过的另一个更笨拙的解决方案是将空格更改为一些辅助字符,然后进行排序,然后将辅助设备更改为空白。

您可以使用'env'程序在排序期间临时更改您的LC_COLLATE; 例如

/ usr / bin / env LC_COLLATE = POSIX / bin / sort file1 file2

在命令行上有点麻烦,但是如果你在脚本中使用它,应该是透明的。

我一直在考虑这一点,希望优化一个shell脚本我维护有一个沉重的国际用户群。 (重量百分比,而不是数量)。

我在网络上看到的大多数选项似乎都推荐我在这里看到的,设置全球的语言环境(过度杀伤)

 export LC_ALL=C 

或者像gnu.org一样把它管道化成每个单独的命令(单调乏味)

 $ echo abcdefghijklmnopqrstuvwxyz | LC_ALL=C /usr/xpg4/bin/tr 'az' 'AZ' ABCDEFGHIJKLMNOPQRSTUVWXYZ 

我想避免用户的语言环境作为运行我的程序的一个看不见的副作用。 事实证明,就像你所期望的那样,通过放弃全球化而轻易完成。 不需要通过程序导出这个变量。

由于某些原因,我必须设置LANG而不是LC_ALL,但是所有的单个语言环境都已经设置好了,这对我来说已经足够了。

这是测试,尽可能简单

 #!/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 ac aa $ sort txt aa ac ab 

我敢打赌,在你的ac之间你有一个非破坏性的空间,一个enspace或者一个empspace或者其他的高codepoint空间!

编辑

只是在Linux上运行它。 我应该看看这些标签。 是的,我得到相同的输出! 我第一次运行在Mac上。 看起来像GNU和BSD之间的区别。 我会进一步调查。

编辑2:

Linux使用基于字段的排序….仍在寻找如何抑制它。 试着

 sort -t, txt 

希望诱使GNU认为整条线是一个字段,但它仍然使用当前的语言环境进行排序。

编辑3:

OP通过将locale设置为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选项,或者一些新的选项将是一个更明智的方式来做到这一点。

顺便说一句,它看起来像这个问题之前曾被问过: 从牛磺酸排序意外的结果 。