Bash Globbing tidak seperti yang diharapkan

8

Ini adalah pertanyaan PR:

Cocokkan semua nama file dengan 2 karakter atau lebih yang dimulai dengan huruf kecil, tetapi jangan diakhiri dengan huruf besar.

Saya tidak mengerti mengapa solusi saya tidak berfungsi.

Jadi saya mengeksekusi di bawah ini:

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

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

Keluaran:

aa  ha

Pertanyaan saya: Mengapa tidak cocok dengan "ah", "hh", atau "a123e"?

Hati gelap
sumber
Bekerja untuk saya dengan benar di bawah mkshshell, tetapi tidak bash --posix, jadi pasti ada beberapa aturan khusus untuk bash`
Sergiy Kolodyazhnyy
@Erg, perhatikan bahwa perilaku untuk [AZ] tidak ditentukan oleh POSIX kecuali di lokal C. mkshseperti zsh's [A-Z]tidak cocok pada Émisalnya. Pertandingan ksh93 [A-Z]aktif Étetapi tidak aktif h.
Stéphane Chazelas

Jawaban:

9

Ini adalah masalah lokal . Di lokal Anda, [A-Z]perluas sesuatu seperti [AbBcZ...zZ](ditambah mungkin yang lain seperti karakter beraksen), karena itu [^A-Z]sebenarnya berarti "file yang diakhiri dengan a" dalam contoh Anda (dan hanya dalam contoh Anda).

Jika Anda ingin menghindari kejutan seperti itu, salah satu caranya adalah mengatur LC_COLLATE=C karena pemeriksaan adalah bagian dari pengaturan lokal Anda yang bertanggung jawab atas urutan penyortiran. Juga, kosongkan LC_ALLjika sudah diatur, karena akan diutamakan.

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

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

Atau, lebih baik, mungkin lebih baik tidak mengubah pengaturan lokal Anda dan menggunakan kelas yang sesuai: [:lower:]alih- alih [a-z]dan [:upper:]bukannya [A-Z].

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

Atau gunakan globasciirangesopsi bash :

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

$ shopt -u globasciiranges
$ ls [a-z]*[^A-Z]
aa  ha
xienne
sumber
@ Heemayl, tidak LC_ALL=C ls [a-z]*[^A-Z]hanya akan mempengaruhi lslokal, bukan lokal yang digunakan oleh shell untuk memperluas glob atau mengurai baris perintah itu.
Stéphane Chazelas
Anda tidak perlu mengekspor LC_xxxagar dapat diterapkan ke glob, tetapi akan lebih disukai sehingga mendapatkan lokasi yang sama.
Stéphane Chazelas
1
Perhatikan bahwa di lokal di mana charset adalah GB18030 misalnya, dengan pendekatan LC_ALL = C, itu akan gagal untuk mencocokkan pada file yang dipanggil test-鏏misalnya karena setelah Anda mengubah charset ke yang dari lokal C, menjadi <0xe7>A. TKI, saat mengganti LC_CTYPE, Anda mendapatkan karakter yang berbeda.
Stéphane Chazelas
1
Perhatikan bahwa saya menduga [AZ] di lokal OP mencakup lebih dari AbBcC ... zZ. Mungkin juga memiliki é, Á(tapi mungkin tidak Ź). TKI, menggunakan [A-Z]sedikit tidak masuk akal di luar C locale.
Stéphane Chazelas
@ StéphaneChazelas Terima kasih atas umpan balik yang sangat baik. Jawaban diperbarui. Saya percaya saya memperhitungkan semuanya.
xhienne