GNU sort 命令在不使用字段分隔符时,对不同长度的单词进行排序的行为是正确的,但仅当使用字段分隔符对多个字段中的一个字段进行排序时,它的行为就不正确了。
以下是不使用字段分隔符时正确的、预期的排序行为:
$ cat /tmp/test0
b
c
ant
a
bcd
bc
cn
$ sort /tmp/test0
a
ant
b
bc
bcd
c
cn
注意,对于所有具有共同字符串前缀的单词,较短的单词排在较长的单词之前。例如,a
在 ant
之前,b
在 bc
之前,bc
在 bcd
之前,等等。这是英语字符串排序的公认标准方式,例如在字典中。
然而,当你尝试对表格数据(如 CSV 文件)进行排序,并在某一列上进行排序时,排序行为就会改变。这是它看起来的样子:
$ cat /tmp/test1
b,foo
c,bar
ant,baz
a,foo
bcd,ty
bc,pe
cn,cn
$ sort /tmp/test1 -t, -k1
a,foo
ant,baz
bcd,ty
bc,pe
b,foo
c,bar
cn,cn
注意,具有共同前缀 a
和 c
的单词仍然被正确处理,但具有共同前缀 b
的字符串没有;bcd
在 bc
之前排序,在 b
之前排序,这都是错误的!这种行为是稳定的;你总是得到相同的结果。我在更大的 CSV 文件上遇到了完全相同的问题,那里的排序错误是确定性的随机的,如果这讲得通的话。
我尝试了各种 sort
的标志,但都没有起到纠正这种行为的作用。-d
和 -s
都不行。这是 GNU coreutils 9.4 sort 的情况,值得一提。
那么,这是否只是 sort
命令的一个错误?我是否以某种方式错误地使用了它?有什么更好的方法可以按第一列中的单词进行字典排序的 CSV 文件吗?
这是因为您当前区域设置定义的排序/排序规则导致的,以及
-kN
在比较行时如何使用字段N
到行尾,而不仅仅是字段N
(有些区域设置会在忽略逗号的情况下将bc,pe
排在b,foo
之前)。使用
-k1,1
只使用那个特定的字段,或者指定 "C" 区域设置,您应该会得到预期的结果:结果表明,尽管网上有些示例用法与之相反,
-k
标志实际上需要两个参数,因此应该写成-k 1,1
。否则,使用-k 1
时,它没有得到一个停止字段编号,因此就会遍历整行。所以,异常的排序行为实际上是由于UTF-8编码的,
分隔符在其他ASCII字符之间的表示所引起的。感谢Stéphane Chazelas在上面的评论。