为什么ls排序会忽略非字母数字字符?


25

在对文件名进行排序时,请ls忽略诸如之类的字符-,_。我希望它也可以使用这些字符进行排序。

一个例子:

touch a1 a2 a-1 a-2 a_1 a_2 a.1 a.2 a,1 a,2

现在显示以下文件ls -1

a1
a_1
a-1
a,1
a.1
a2
a_2
a-2
a,2
a.2

我所期望的是这样的:

a1
a2
a,1
a,2
a.1
a.2
a_1
a_2
a-1
a-2

即我希望排序时要考虑非字母数字字符。

谁能解释这种行为?此行为是由标准强制执行的吗?还是因为编码为UTF-8?

更新:看来这与UTF-8排序有关:

$ LC_COLLATE=C ls -1
a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2

2
如果您使用的只是前128个代码点(您的示例是),则UTF-8和ASCII相同。如果这样做会LC_COLLATE=C ls怎样?
Alexios

问题不在于ASCII和UTF-8是相同的,而是UTF-8具有自己的排序规则(排序)。
丹尼尔·库尔曼2012年

1
是的,确实[_-,.]是正在分组并且以某种方式被半忽略。我不知道如何或在何处定义这种排序规则,但这肯定是一个排序规则问题,因为简单而唯一地将排序规则更改为C(通过LC_COLLATE=C ls -l)就足以为您提供期望的排序顺序(假设LC_ALL是不覆盖LC_COLLATE)。这适用于Unicode Basic Multilingual Plane中的所有字符...我已经编辑了答案,以包含一个示例脚本来证明这一点……
Peter.O 2012年

如果您不喜欢它的工作方式,则可以创建一个别名并将其放在〜/ .profile中:alias ls ='LC_COLLATE = C ls'</ kbd>
jippie 2012年

Answers:


10

这与字符集无关。而是由语言决定排序顺序。libc中检查该语言显示$LC_COLLATE/ $LC_ALL/ $LANG并查找其归类规则(如/usr/share/i18n/locales/*为执导的glibc)和订单的文本。


仅供参考:比这更复杂。strcoll例如,如果要使用,您会看到aasa.c在上面会排序类似的内容aas.c
唐·斯科特

12

编辑:添加了对使用LC_COLLATE = C排序的数据的测试


默认的整理顺序将那些“标点类型”字符视为具有相等的值,Use LC_COLLATE=C以按代码点顺序对待它们。

for i in 'a1' 'a_1' 'a-1' 'a,1' 'a.1' 'a2' 'a_2' 'a-2' 'a,2' 'a.2' ;do
  echo $i; 
done |LC_COLLATE=C sort

输出量

a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2

以下代码测试基本多语言平面中的所有有效 UTF-8字符(为简便起见,除了\ x00\ x0a),
它将以已知(生成的)升序对文件进行比较,然后对该文件进行随机排序,然后使用LC_COLLATE = C。结果表明,C序列与原始产生的序列相同。

{ i=0 j=0 k=0 l=0
  for i in {0..9} {A..F} ;do
  for j in {0..9} {A..F} ;do
  for k in {0..9} {A..F} ;do
  for l in {0..9} {A..F} ;do
     (( 16#$i$j$k$l == 16#0000 )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l == 16#000A )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#D800    && 
        16#$i$j$k$l <= 16#DFFF )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#FFFE )) && { printf '.' >&2; continue; }
     echo 0x"$i$j$k$l" |recode UTF-16BE/x4..UTF-8 || { echo "ERROR at codepoint $i$j$k$l " >&2; continue; } 
     echo 
  done
  done
  done; echo -n "$i$j$k$l " >&2
  done; echo >&2
} >listGen

             sort -R listGen    > listRandom
LC_COLLATE=C sort    listRandom > listCsort 

diff <(cat listGen;   echo "last line of listOrig " ) \
     <(cat listCsort; echo "last line of listCsort" )
echo 
cmp listGen listCsort; echo 'cmp $?='$?

输出:

63485c63485
< last line of listOrig 
---
> last line of listCsort

cmp $?=0

2
记录在哪里?那是Unicode标准的一部分吗?
丹尼尔·库尔曼

2
实际上,它们没有获得相同的价值。这些字符在排序时将被忽略。如果将它们视为具有相等的值,则排序顺序a_1 a2 a_2将是不可能的。
丹尼尔·库尔曼2012年

+1为您的辛勤工作和示例代码。在经过数小时的整理后tree,我用标点符号对目录名称进行了排序,以使其与之匹配,我认为故事中还有更多内容,例如从比较字符串中删除标点符号之类的东西。我可以说/无论其他情况如何,都必须将该字符设置为整理序列中的最低字符。
WinEunuuchs2Unix
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.