Tại sao ls sắp xếp bỏ qua các ký tự không chữ và số?


25

Khi sắp xếp tên tệp, lsbỏ qua các ký tự như -,_. Tôi dự kiến ​​nó cũng sẽ sử dụng những ký tự đó.

Một ví dụ:

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

Bây giờ hiển thị các tệp này với ls -1:

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

Những gì tôi mong đợi là một cái gì đó như thế này:

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

tức là tôi dự kiến ​​các ký tự không chữ và số sẽ được tính đến khi sắp xếp.

Bất cứ ai có thể giải thích hành vi này? Là hành vi này được ủy quyền bởi một tiêu chuẩn? Hay điều này là do mã hóa là UTF-8?

Cập nhật: Có vẻ như điều này có liên quan đến sắp xếp 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
UTF-8 và ASCII giống hệt nhau nếu tất cả những gì bạn đang sử dụng là 128 điểm mã đầu tiên (ví dụ của bạn là). Điều gì xảy ra nếu bạn làm gì LC_COLLATE=C ls?
Alexios

Vấn đề không phải là ASCII và UTF-8 giống hệt nhau, mà là UTF-8 có các quy tắc đối chiếu (sắp xếp) riêng.
daniel kullmann

1
Vâng, đúng là [_-,.]đang được nhóm lại và bằng cách nào đó bị bỏ qua. Tôi không biết chính xác làm thế nào hoặc ở đâu đối chiếu như vậy được xác định, nhưng nó phải là một vấn đề đối chiếu, bởi vì đơn giản, và chỉ, thay đổi đối chiếu thành C (thông qua LC_COLLATE=C ls -l) là đủ để cung cấp cho bạn thứ tự sắp xếp mà bạn mong đợi (giả sử LC_ALLlà không ghi đè LC_COLLATE). Điều này đúng với toàn bộ phạm vi các ký tự trong Mặt phẳng đa ngôn ngữ cơ bản Unicode ... Tôi đã chỉnh sửa câu trả lời của mình để bao gồm một tập lệnh mẫu có nội dung này ...
Peter.O

nếu bạn không thích cách nó hoạt động, bạn có thể tạo bí danh và đặt nó vào ~ / .profile: alias ls = 'LC_COLLATE = C ls' </ kbd>
jippie

Câu trả lời:


10

Điều này không có gì để làm với bộ ký tự. Thay vào đó, đó là ngôn ngữ xác định thứ tự đối chiếu. Libc kiểm tra ngôn ngữ được trình bày trong $LC_COLLATE/ $LC_ALL/ $LANGvà tìm kiếm các quy tắc đối chiếu của nó (ví dụ: /usr/share/i18n/locales/*đối với GLibC) và sắp xếp văn bản theo chỉ dẫn.


FYI: Nó phức tạp hơn thế này. Nếu một người sử dụng strcollchẳng hạn, bạn sẽ thấy một cái gì đó giống như aasa.csẽ được sắp xếp ở trên aas.c.
Don Scott

12

EDIT: Đã thêm kiểm tra cho dữ liệu được sắp xếp với LC_COLLATE = C


Trình tự đối chiếu mặc định đang coi các ký tự "kiểu chấm câu" đó có giá trị như nhau .. Use LC_COLLATE=Cđể xử lý chúng theo thứ tự mã hóa ..

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

Đầu ra

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

Đoạn mã sau kiểm tra tất cả các ký tự UTF-8 hợp lệ trong Mặt phẳng đa ngôn ngữ cơ bản (ngoại trừ \ x00\ x0a ; để đơn giản)
Nó so sánh một tệp theo trình tự tăng dần đã biết (được tạo), so với tệp đó được sắp xếp ngẫu nhiên và sau đó được sắp xếp lại với LC_COLLATE = C. Kết quả cho thấy chuỗi C giống hệt với chuỗi được tạo ban đầu.

{ 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 $?='$?

Đầu ra:

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

cmp $?=0

2
Tài liệu đó ở đâu? Đó có phải là một phần của tiêu chuẩn Unicode không?
daniel kullmann

2
Thật ra, họ không nhận được cùng một giá trị; những ký tự đó chỉ đơn giản là bị bỏ qua khi sắp xếp. Nếu chúng được coi là có giá trị bằng nhau, thứ tự sắp xếp a_1 a2 a_2sẽ là không thể.
daniel kullmann

+1 cho công việc khó khăn và mã mẫu của bạn. Sau nhiều giờ sắp xếp các tên thư mục có dấu chấm câu để khớp với cách treetôi nghĩ có nhiều câu chuyện như dấu chấm câu được loại bỏ khỏi chuỗi so sánh hoặc đại loại như thế. Tôi có thể nói /nhân vật phải được đặt là nhân vật thấp nhất trong chuỗi đối chiếu bất kể điều gì khác.
WinEunuuchs2Unix
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.