Đó là hậu quả của những nhân vật có cùng thứ tự sắp xếp.
Bạn cũng sẽ nhận thấy rằng
sort -u << EOF
■
⅕
⅖
⅗
EOF
chỉ trả về một dòng.
Hoặc đó:
expr ■ = ⅕
trả về true (theo yêu cầu của POSIX).
Hầu hết các địa phương được vận chuyển với các hệ thống GNU có một số ký tự (và thậm chí các chuỗi ký tự (các chuỗi đối chiếu)) có cùng thứ tự sắp xếp. Trong trường hợp của những cái đó, đó là vì thứ tự không được xác định và những ký tự có thứ tự không được xác định cuối cùng có cùng thứ tự sắp xếp trong các hệ thống GNU. Có những ký tự được xác định rõ ràng là có cùng thứ tự sắp xếp như và (mặc dù không có logic thực sự rõ ràng (với tôi dù thế nào) hoặc tính nhất quán về cách thực hiện).
Đó là nguồn gốc của những hành vi khá bất ngờ và không có thật. Gần đây tôi đã đưa ra vấn đề về nhóm Austin (cơ quan đứng sau danh sách gửi thư của POSIX và Thông số kỹ thuật UNIX đơn) và cuộc thảo luận vẫn đang tiếp diễn kể từ 2015-04-03.
Trong trường hợp này, liệu có [y]
nên khớp với x
vị trí x
và y
sắp xếp giống nhau không rõ ràng đối với tôi, nhưng vì biểu thức ngoặc có nghĩa là khớp với phần tử đối chiếu, điều đó cho thấy rằng bash
hành vi được mong đợi.
Trong mọi trường hợp, tôi cho rằng [⅕-⅕]
hoặc ít nhất [⅕-⅖]
nên phù hợp ■
.
Bạn sẽ nhận thấy rằng các công cụ khác nhau hành xử khác nhau. ksh93 hành xử như bash
, GNU grep
hoặc sed
không. Một số shell khác có hành vi khác nhau, một số như yash
thậm chí nhiều lỗi hơn.
Để có một hành vi nhất quán, bạn cần một miền địa phương nơi tất cả các nhân vật sắp xếp khác nhau. Địa phương C là một điển hình. Tuy nhiên, ký tự được đặt trong miền địa phương C trên hầu hết các hệ thống là ASCII. Trên các hệ thống GNU, bạn thường có quyền truy cập vào một C.UTF-8
ngôn ngữ có thể được sử dụng thay thế để hoạt động trên ký tự UTF-8.
Vì thế:
(export LC_ALL=C.UTF-8; [[ ■ = [⅕⅖⅗] ]])
hoặc tương đương tiêu chuẩn:
(export LC_ALL=C.UTF-8
case ■ in ([⅕⅖⅗]) true;; (*) false; esac)
nên trả lại sai.
Một cách khác là chỉ đặt thành LC_COLLATE
C hoạt động trên các hệ thống GNU, nhưng không nhất thiết phải ở các hệ thống khác, nơi nó không thể chỉ định thứ tự sắp xếp của ký tự nhiều byte.
Một bài học về điều đó là sự bình đẳng không phải là một khái niệm rõ ràng như người ta mong đợi khi so sánh các chuỗi. Bình đẳng có thể có nghĩa, từ nghiêm ngặt nhất đến ít nghiêm ngặt nhất.
- Cùng một số byte và tất cả các thành phần byte có cùng giá trị.
- Cùng một số ký tự và tất cả các ký tự đều giống nhau (ví dụ: tham khảo cùng một mật mã trong bộ ký tự hiện tại).
- Hai chuỗi có thứ tự sắp xếp giống nhau theo thuật toán đối chiếu của miền địa phương (nghĩa là không phải <b hay b> a là đúng).
Bây giờ, cho 2 hoặc 3, giả sử cả hai chuỗi chứa các ký tự hợp lệ. Trong UTF-8 và một số mã hóa khác, một số chuỗi byte không tạo thành các ký tự hợp lệ.
1 và 2 không nhất thiết phải tương đương vì điều đó hoặc vì một số ký tự có thể có nhiều hơn một mã hóa có thể. Đó thường là trường hợp mã hóa trạng thái như ISO-2022-JP A
có thể được biểu thị bằng 41
hoặc 1b 28 42 41
( 1b 28 42
là chuỗi để chuyển sang ASCII và bạn có thể chèn bao nhiêu trong số đó nếu muốn, điều đó sẽ không tạo ra sự khác biệt), mặc dù tôi sẽ không mong đợi các loại mã hóa đó vẫn đang được sử dụng và các công cụ GNU ít nhất thường không hoạt động đúng với chúng.
Cũng cần lưu ý rằng hầu hết các tiện ích không phải GNU không thể xử lý giá trị 0 byte (ký tự NUL trong ASCII).
Những định nghĩa nào được sử dụng phụ thuộc vào phiên bản hoặc tiện ích và triển khai tiện ích. POSIX không rõ ràng 100% về điều đó. Trong miền địa phương C, cả 3 đều tương đương. Bên ngoài YMMV đó.