UNIX排序忽略空格

时间:2011-08-03 08:13:03

标签: linux shell sorting locale

给定文件txt

ab
a c
a a

致电sort txt时,我获得了:

a a
ab
a c

换句话说,它不是正确的排序,它有点删除/忽略空白!我希望这是sort -i的行为,但无论有没有-i标志,都会发生这种情况。

我想获得“正确”的排序:

a a
a c
ab

我该怎么做?

7 个答案:

答案 0 :(得分:15)

解决方案:

export LC_ALL=C

From the sort() documentation

  

警告:环境指定的区域设置会影响排序顺序。设置LC_ALL = C以获取使用本机字节值的传统排序顺序。

(至少适用于ASCII,不知道UTF8)

答案 1 :(得分:11)

如前所述,LC_ALL=C sort可以解决问题。这仅仅是因为不同的语言对字符排序有不同的规则,这些规则通常由高级语言学家而不是CS专家来规划。对于您的语言环境,这些规则似乎表明在排序时应该忽略空格。

通过前缀LC_ALL = C(或者,当LC_ALL未设置,LC_COLLATE=C就足够了)时,您明确声明与语言无关的排序(以及使用LC_ALL,数字格式和填充),这是您想要的这个背景。如果您想将其设为默认值,请在您的环境中导出LC_COLLATE。

以这种方式选择默认值以保持与“普通”真实世界排序方案(如白页)的一致性,这些方案通常会忽略空格。

答案 2 :(得分:2)

您可以使用'env'程序在排序期间临时更改您的LC_COLLATE; e.g。

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

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

答案 3 :(得分:2)

使用C语言环境,即仅按字节值排序在某些字母超出范围[A-Za-z]的语言中不是一个好的解决方案。这些字母在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就可以了。我尝试的另一个但更笨拙的解决方案是将空格更改为某些辅助字符,然后排序,然后将辅助设备更改为空白。

答案 4 :(得分:1)

我一直在研究这个问题,想要优化我维护的具有大量国际用户群的shell脚本。 (重量百分比,而不是数量)。

我在网上看到的大多数选项似乎都推荐我在这里看到的,全局设置区域设置(矫枉过正)

export LC_ALL=C

或从gnu.org(乏味)

将其汇总到每个单独的命令中
$ echo abcdefghijklmnopqrstuvwxyz | LC_ALL=C /usr/xpg4/bin/tr 'a-z' 'A-Z' 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=

你去吧。您可以获得优化的区域设置,而不会破坏另一个人的无辜环境,并避免在您认为可能有用的任何地方进行管道繁琐。

答案 5 :(得分:0)

其实对我来说

$ cat txt
ab
a c
a a
$ sort txt
a a
a c
ab

我会在你的ac之间打赌你有一个不间断的空间或者一个空间或一个空间或其他高码点空间!

修改

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

编辑2:

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

sort -t, txt

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

编辑3:

OP通过使用

将语言环境设置为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上提出过:unexpected result from gnu sort

答案 6 :(得分:0)

很奇怪,在这里工作(cygwin)。

尝试sort -d txt