为什么ls
以看似不同的顺序列出以下文件?
默认情况下,不会ls
按我当前语言环境的字典顺序列出文件,我猜这是默认的?
$ ls
a_1 a_10 a_11 a_12
$ ls
a_10-18 a_11-18 a_1-18 a_12-18
我有alias ls='ls --color=auto'
和LC_COLLATE="en_US.UTF-8"
。
答案1
语言环境确实很复杂。目的是让非技术用户“感觉正常”。 (技术人员可以使用LANG=C
它来获得那种温暖模糊的感觉。)技术定义是Unicode 标准文档,我试图在这里提炼一些内容。很高兴收到更正。
我觉得读起来很有趣语言环境是处理数据的用户的属性,而不是数据本身的属性。尽管示例字符串中使用的字符相同,但该技术文档还是用了一定的篇幅来阐明这一点,即德国用户的排序顺序与瑞典用户的排序顺序不同。
en_GB 和 en_US 语言环境设置为忽略该-
字符。这些区域设置的升序排序规则非常简单:
- 不区分大小写
- 如果您有两个字符串,它们最初相同,只是其中一个较长,那么它会排在第二位。所以
xyzA
总是在之后xyz
-
除非与其他标点符号进行比较,否则某些标点符号(在这种情况下包括)将被忽略- 数字在字母之前排序
- 数字已排序
0
..9
- 字母已排序
[Aa]
..[Zz]
(en_GB 和 en_US 并没有真正的重音符号) - 对于任何给定的字母,小写字母排在大写字母之前(因此
one
位于 之前One
,但两者都位于 之前two
) - 标点符号已排序(但与此答案中的示例无关)
将这些规则应用于相关数据集:
a_1 a_10 a_11 a_12
这相当于a1
a10
a11
a12
, 并且考虑到规则#2,我们得到a1
必须在a10
和之前a11
。除此以外的所有内容a1
都具有相同数量的字母数字字符,因此可以一致地比较它们。这给了我们a_1
a_10
a_11
a_12
.
a_10-18 a_11-18 a_1-18 a_12-18
相同的规则适用,除了 #3 也适用(我们忽略标点符号)。这意味着我们可以将这些值视为a_1018
a_1118
a_118
a_1218
,并按照规则 #2 和 #4 我们得到顺序a_10-18
a_11-18
a_1-18
a_12-18
。
以评论中的最后一个例子为例
a_10 a_10- a_100 a_101 a_10-18 a_102
适用规则 #3,然后适用规则 #2、#4。因此,我们删除(忽略)-
给出 的字符a_10
a_10
a_100
a_101
a_1018
a_102
,并按公共子字符串前缀然后按字符顺序对剩余部分进行排序。
(我不清楚我们是否会因为长度a_10
而得到然后,或者只是因为它恰好以这种方式结束。我很想建议后者,但我希望有人能证实这一点。)a_10-
答案2
按照字典顺序,a_1
位于以 开头的任何其他字符串之前a_1
。由于数字在任何合理的区域设置中都按数字顺序排列,因此在任何合理的区域设置中,a_1
< a_10
< a_11
< a_12
。
如果向这些字符串添加公共后缀,则顺序可能会发生变化,因为该公共后缀可能会排序在中间的某个位置。在第二个示例中,有四个字符串以公共前缀 开头,a_1
并分别带有后缀0-18
、1-18
和。在 C 语言环境中,字符串是按照严格的字典顺序进行比较的;出现在数字之前,因此先出现:< < < 。但大多数其他语言环境更为复杂。特别是,除非作为最后手段,否则标点符号会被忽略。因此,要比较字符串 < < < ,首先比较无标点符号字符串, ;第二个数字的顺序是< < < ,中间两个字符串的第三个数字的顺序是< 。如果添加仅标点符号不同的字符串,则不同的标点符号将决定其排序方式,例如< < <-18
2-18
-
-18
a_10-18
a_11-18
a_1-18
a_12-18
a_10-18
a_11-18
a_1-18
a_12-18
a1018
a1118
a118
a1218
0
1
1
2
1
8
a_10-18
a_1-118
a_11-18
a_12-18
我的回答中的解释很简单。可以有两次以上的传递,以处理标点符号之类的问题。这重症监护病房用户指南有一个相当详细的解释(但即使如此,也没有处理对书籍索引等内容进行排序的所有微妙之处)。