Bash Globbing không như mong đợi


8

Đây một câu hỏi bài tập về nhà:

Khớp tất cả tên tệp có 2 hoặc nhiều ký tự bắt đầu bằng chữ in thường, nhưng không kết thúc bằng chữ in hoa.

Tôi không hiểu tại sao giải pháp của tôi không hiệu quả.

Vì vậy, tôi đã thực hiện như sau:

touch aa
touch ha
touch ah
touch hh
touch a123e
touch hX
touch Ax

ls [a-z]*[!A-Z]

Đầu ra:

aa  ha

Câu hỏi của tôi: Tại sao nó không khớp với "ah", "hh" hoặc "a123e"?


Làm việc cho tôi đúng cách dưới mkshvỏ, nhưng không bash --posix, vì vậy phải có một số quy tắc cụ thể cho bash`
Sergiy Kolodyazhnyy

@Serg, lưu ý rằng hành vi của [AZ] không được chỉ định bởi POSIX ngoại trừ trong miền C. mkshnhư zsh's [A-Z]không phù hợp trên Éví dụ. [A-Z]trận đấu của ksh93 Énhưng không phải trên h.
Stéphane Chazelas

Câu trả lời:


9

Đây là một vấn đề địa phương . Trong ngôn ngữ của bạn, [A-Z]mở rộng thành một cái gì đó như [AbBcZ...zZ](cộng với những người khác như các ký tự có dấu), do đó [^A-Z]thực sự có nghĩa là "các tệp kết thúc bằng a" trong ví dụ của bạn (và chỉ trong ví dụ của bạn).

Nếu bạn muốn tránh sự bất ngờ như vậy, một cách là đặt LC_COLLATE=C vì đối chiếu là một phần của cài đặt ngôn ngữ chịu trách nhiệm về thứ tự sắp xếp. Ngoài ra, trống LC_ALLnếu nó được đặt, vì nó sẽ được ưu tiên.

$ ls [a-z]*[^A-Z]
aa  ha

$ ( LC_ALL=; LC_COLLATE=C; ls [a-z]*[^A-Z] )
a123e  aa  ah  ha  hh

Hoặc, tốt hơn, có lẽ không nên thay đổi cài đặt ngôn ngữ của bạn và sử dụng các lớp thích hợp: [:lower:]thay vì [a-z][:upper:]thay vì [A-Z].

$ ls [[:lower:]]*[^[:upper:]]
a123e  aa  ah  ha  hh

Hoặc sử dụng globasciirangestùy chọn của bash :

$ shopt -s globasciiranges
$ ls [a-z]*[^A-Z]
a123e  aa  ah  ha  hh

$ shopt -u globasciiranges
$ ls [a-z]*[^A-Z]
aa  ha

@heemayl, không LC_ALL=C ls [a-z]*[^A-Z]chỉ ảnh hưởng đến lsmiền địa phương, không phải miền được sử dụng bởi trình bao để mở rộng toàn cầu hoặc phân tích dòng lệnh đó.
Stéphane Chazelas

Bạn không cần phải xuất LC_xxxcho nó để áp dụng cho toàn cầu, nhưng sẽ tốt hơn vì vậy tôi sẽ có cùng địa phương.
Stéphane Chazelas

1
Lưu ý rằng trong một miền địa phương nơi charset là GB18030 ví dụ, với LC_ALL = cách tiếp cận C, nó sẽ không phù hợp trên một tập tin gọi là test-鏏ví dụ bởi vì một khi bạn thay đổi charset cho rằng các locale C, trở thành <0xe7>A. IOW, khi thay đổi LC_CTYPE, bạn sẽ nhận được các ký tự khác nhau.
Stéphane Chazelas

1
Lưu ý rằng tôi nghi ngờ [AZ] trong miền địa phương của OP bao phủ nhiều hơn AbBcC ... zZ. Nó có lẽ cũng có é, Á(nhưng có lẽ là không Ź). IOW, sử dụng [A-Z]có ý nghĩa nhỏ bên ngoài miền địa phương C.
Stéphane Chazelas

@ StéphaneChazelas Cảm ơn bạn đã phản hồi tuyệt vời. Trả lời cập nhật. Tôi tin rằng tôi đã tính đến mọi thứ.
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.