Mengapa [az] asterisk cocok dengan angka?

13

Saya memiliki 3 direktori di jalur saat ini.

$ls
a_0db_data  a_clean_0db_data  a_clean_data
$ls a_*_data
a_0db_data:

a_clean_0db_data:

a_clean_data:

$ls a_[a-z]*_data
a_clean_0db_data:

a_clean_data:

Saya berharap perintah terakhir hanya cocok a_clean_data. Mengapa itu juga cocok dengan yang mengandung 0?

bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)
pengguna13107
sumber
2
Lihat pertanyaan ini untuk lebih lanjut tentang perbedaan antara ekspresi reguler dan gumpalan.
terdon
4
Jadi fakta yang a_*_datacocok dengan `semua file ini tidak mengejutkan Anda?
Cthulhu
@ Cthulhu Anda menangkap saya!
user13107

Jawaban:

29

Bagian [a-z]ini tidak cocok dengan nomor tersebut; itu adalah *. Anda mungkin membingungkan shell globbing dan ekspresi reguler .

Alat seperti grepmenerima berbagai rasa regex ( dasar secara default, -Euntuk extended, -Puntuk Perl regex )

Misalnya ( -vmembalikkan pertandingan)

$ ls a_[a-z]*_data | grep -v "[0-9]"
a_clean_data

Jika Anda ingin menggunakan bash regex, berikut adalah contoh tentang cara menguji apakah variabel $reftersebut bilangan bulat:

re='^[0-9]+$'
if ! [[ $ref =~ $re ]] ; then
  echo "error"
fi
Sebastian
sumber
Bagaimana cara menggunakan bash regex? (lihat tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_01.html )
user13107
1
lihat pertanyaan ini
umläute
21

Jadi masalahnya adalah: mengapa a_[a-z]*_datacocok a_clean_0db_data?

Ini dapat dipecah menjadi empat bagian:

  • a_cocok dengan awal a_clean_0db_data, meninggalkan clean_0db_datauntuk dicocokkan

  • [a-z]cocok dengan karakter apa pun dalam rentang a-z(mis. c), membiarkan lean_0db_datadicocokkan

  • * cocok dengan sejumlah karakter, mis lean_0db

  • _data cocok dengan trailing _data

Dalam ekspresi reguler, [a-z]*berarti sejumlah karakter (termasuk nol) dalam kisaran a..z , tetapi Anda berhadapan dengan shell globbing, bukan dengan ekspresi reguler.

Jika Anda ingin ekspresi reguler, beberapa findimplementasi memiliki -regexpredikat untuk itu:

find . -maxdepth 1 -regex "^.*/a_[a-z]*_data$"

The -maxdepthhanya di sini untuk membatasi pencarian hasil ke folder Anda berada di. The ekspresi reguler sesuai dengan seluruh nama file, karena itu saya telah menambahkan ^.*/untuk mencocokkan jalur-bagian

umläute
sumber
11

*dalam pola shell cocok dengan 0 atau lebih karakter. Tidak perlu bingung dengan *operator ekspresi reguler yang berarti 0 atau lebih dari atom sebelumnya .

Tidak ada padanan regexp *dalam pola dasar shell. Namun, berbagai shell memiliki ekstensi untuk itu.

  • kshmemiliki *(something):

    ls a_*([a-z])_data
  • Anda dapat memiliki hal yang sama bashdengan shopt -s extglobatau zshdengan setopt kshglob:

    shopt -s extglob
    ls a_*([a-z])_data
  • Dalam zshdengan extendedglobdiaktifkan, #setara dengan regexp *:

    setopt extendedglob
    ls a_[a-z]#_data
  • Di versi terbaru ksh93, Anda juga dapat menggunakan ekspresi reguler di gumpalan. Di sini dengan ekspresi reguler yang diperluas :

    ls ~(E:a_[a-z]*_data)

Perhatikan bahwa [a-z]cocok dengan berbagai hal tergantung pada lokal saat ini. Secara umum hanya cocok 26 ake zhuruf latin non-aksen di Clokal. Di tempat lain, umumnya lebih cocok, dan tidak selalu masuk akal. Untuk mencocokkan huruf di lokal Anda, Anda dapat memilih [[:alpha:]].

Stéphane Chazelas
sumber
Bisakah Anda memberikan contoh yang [a-z]lebih cocok dengan 26 huruf yang cocok dengan bahasa C? Apa yang saya ingat dari ketika saya terakhir kali melihat ini, semua pengkodean praktis digunakan dalam varian Unix memiliki ISO-646 sebagai basis (kemudian 128 kode atas di mana digunakan secara berbeda, langsung untuk karakter dalam pengkodean seperti ISO-8859-X, digabungkan dalam pengkodean seperti UTF-8 atau keluarga EUC). Bahkan AIX tidak memiliki lokal EBCDIC (setidaknya tersedia untuk saya). Saya ingat berusaha menemukan apakah standar POSIX / UNIX menuntutnya, tetapi saya tidak ingat hasilnya.
Pemrogram
1
@AProgrammer, itu independen terhadap pengkodean, yang didasarkan pada urutan sortir (LC_COLLATE). [a-z]umumnya menyertakan éatau í(tetapi tidak harus ź) di locales tempat charset memilikinya, apakah codepoint dalam pengkodean itu antara a dan z atau tidak. Hanya lokal C yang menjamin urutan sortir berdasarkan nilai codepoint. Lihat jawaban lain ini untuk lebih jelasnya.
Stéphane Chazelas
Ok, yang saya lewatkan adalah bahwa jangkauan ditafsirkan sesuai dengan urutan pemeriksaan saat ini.
Pemrogram