Biểu thức khung (không có phạm vi) khớp với ký tự không mong muốn trong bash


20

Tôi đang sử dụng bash trên Linux. Tôi đang nhận được thành công từ câu lệnh if sau, nhưng điều này có nên trả về mã thất bại không?

if [[  = [⅕⅖⅗] ]] ; then echo yes ; fi

Hình vuông KHÔNG bằng bất kỳ ký tự nào, vì vậy tôi không hiểu tại sao tôi nhận được mã thành công.

Điều quan trọng đối với tôi là giữ dấu ngoặc kép trong trường hợp của mình.

Có cách nào khác để thực hiện một phạm vi trong kịch bản này, hoặc bất kỳ đề xuất nào khác không?


2
Có lẽ là hậu quả của tất cả những nhân vật có thứ tự sắp xếp không xác định trong ngôn ngữ của bạn (và do đó sắp xếp giống nhau). Xem các cuộc thảo luận liên quan, đang diễn ra tại nhóm Austin . Thay đổi miền địa phương thành C để sửa nó .
Stéphane Chazelas

1
Xin lỗi, Csẽ không làm ở đây vì nó không phải là ký tự một byte. C.UTF-8sẽ làm nơi có sẵn.
Stéphane Chazelas

11
Xin chúc mừng, bạn đã quản lý để triệu tập Stéphane đang nắm giữ một chuỗi Austin Group trong câu hỏi đầu tiên của bạn. Điều đó phải có giá trị ít nhất của một Internets. Hoặc hoặc thậm chí ■ Internets, vì rõ ràng là giống nhau. Chào mừng bạn đến với Unix & Linux , và hãy tiếp tục mang đến những câu hỏi thú vị.
derobert

Câu trả lời:


29

Đó 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 xvị trí xysắ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 bashhà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 grephoặc sedkhông. Một số shell khác có hành vi khác nhau, một số như yashthậ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-8ngô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_COLLATEC 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.

  1. Cùng một số byte và tất cả các thành phần byte có cùng giá trị.
  2. 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).
  3. 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 Acó thể được biểu thị bằng 41hoặc 1b 28 42 41( 1b 28 42là 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 đó.


Một trường hợp phổ biến khác khi 1 và 2 khác nhau là bằng Unicode với những thứ như kết hợp các ký tự.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles, kết hợp các nhân vật là các nhân vật của riêng họ. Sự kết hợp tạo thành một biểu đồ / ô, nhưng vẫn được hình thành từ một số ký tự. é (U + 00E9) và é (e theo sau là U + 0301) là cùng một biểu đồ, nhưng hai chuỗi ký tự khác nhau (ít nhất là theo quan điểm của API POSIX). Bởi 1 và 2, chúng sẽ khác nhau. Đến 3, họ có thể cân nhắc như nhau nếu U + 0301 có tất cả các trọng số đối chiếu của nó được đặt thành "IGNORE", nhưng đó thường không phải là trường hợp như người ta thường muốn quyết định theo thứ tự dấu phụ.
Stéphane Chazelas

Nó thường được mong muốn để xem xét élà cùng một chuỗi, nhưng không e. Khái niệm về thứ tự đối chiếu của POSIX hiếm khi đúng, nó quá nhiều dựa trên các ký tự và không tính đến hầu hết các cách sắp xếp chuỗi phổ biến (ví dụ: từ điển tiếng Pháp không sử dụng thứ tự từ vựng để sắp xếp các từ: chúng thực hiện một từ vựng đầu tiên có dấu bị bỏ qua và sau đó sử dụng dấu để quyết định quan hệ).
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles, vâng. Đó là lý do tại sao tôi nói rằng những nhân vật có thứ tự sắp xếp giống nhau (chủ ý) trong các địa phương glibc có ý nghĩa rất nhỏ. Vs vs é thường được xử lý bằng cách thực hiện một số chuyển đổi trên các chuỗi trước tiên như phân tách chính tắc (tương tự như chuyển đổi sang chữ thường trước khi bạn muốn thực hiện sắp xếp / khớp không phân biệt chữ hoa chữ thường). Xem thêm hướng dẫn ICU để biết một số tài liệu tham khảo tốt về chủ đề này.
Stéphane Chazelas

@Gilles, các trọng số trong thuật toán đối chiếu miền POSIX có thể thực hiện việc sắp xếp từ điển tiếng Pháp đó. Đó là cách các trọng lượng làm việc. Vượt qua đầu tiên sử dụng các trọng số chính (trong đó e và é (và E và É) giống nhau và dấu trọng âm kết hợp bị bỏ qua) một vượt qua thứ hai (nếu bằng nhau) kiểm tra các dấu, viết hoa qua 3 ...
Stéphane Chazelas

-3

Bạn đang làm sai, ===không giống nhau.

Hãy thử những ví dụ sau:

if [[ "■" == "[⅕⅖⅗]" ]] ; then echo yes ; else echo no ; fi

if [[ "1" == "1" ]] ; then echo yes ; else echo no ; fi

if [[ "■" == "■" ]] ; then echo yes ; else echo no ; fi

1
Đo không phải sự thật. POSIX chỉ định rằng toán tử =nên được sử dụng để kiểm tra sự bằng nhau. Vấn đề là các trích dẫn bị thiếu, không phải là nhà điều hành.
scai

1
Cũng man bashnói trong [[phần: "Toán tử = tương đương với ==."
michas

1
@scai, POSIX không chỉ định [[...]]toán tử. Và = và == giống nhau trong các shell được triển khai (ksh / bash / zsh) và để khớp mẫu, không phải là đẳng thức.
Stéphane Chazelas

Khi so sánh với một mẫu, mẫu không được trích dẫn, nếu không nó được lấy dưới dạng một chuỗi ký tự, do đó "không" trong thử nghiệm đầu tiên.
xhienne
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.