Apakah ada alasan historis mengapa Bash "globbing" dan ekspresi reguler tidak identik? Sebagai contoh, saya percaya bahwa di Bash [1-2]*
cocok dengan apa pun yang dimulai dengan 1 atau 2 diikuti oleh yang lain, sedangkan sebagai ekspresi reguler [1-2]*
hanya akan cocok dengan urutan 1s dan 2s. Script Bash dan REGEX foo saya berdua sangat lemah dan saya sering mengalami masalah yang terkait dengan perbedaan-perbedaan ini yang membuat saya penasaran mengapa mereka berbeda.
shell
regular-expression
wildcards
history
StrongBad
sumber
sumber
rm -- ^[^.].*\.txt$
bukanrm -- *.txt
?find . -regex ".*\.txt$" | xargs rm --
ataurename
untuk mengganti nama file (itused
untuk nama file), berhati-hatilah beberapa sistem memiliki yang berbedarename
.^[^.].*\.txt$
harus memperhitungkan pengabaian file dot. Perhatikan bahwa-regex
adalah ekstensi GNU, beberapa shell seperti ksh93 atau zsh dapat menggabungkan regexps dalam gumpalan mereka (coba misalnya:ksh93 -c 'echo ~(E:^[^.].*\.txt$)'
)Jawaban:
bash
awalnya dirancang pada akhir 80-an sebagai tiruan sebagianksh
dengan beberapa fitur interaktif dari csh / tcsh.Asal usul globbing harus ditemukan dalam cangkang-cangkang sebelumnya yang menjadi dasarnya.
ksh
sendiri merupakan perpanjangan dari shell Bourne. Shell Bourne itu sendiri (pertama kali dirilis pada tahun 1979 di Unix V7) adalah implementasi bersih dari awal, tetapi tidak sepenuhnya berangkat dari shell Thompson (shell V1 -> V6) dan memasukkan fitur dari shell Mashey.Secara khusus, argumen perintah masih dipisahkan oleh kosong,
|
sekarang operator pipa baru tetapi^
masih didukung sebagai alternatif (dan juga menjelaskan mengapa Anda melakukannya[!a-z]
dan tidak[^a-z]
),$1
masih argumen pertama untuk skrip dan backslash masih karakter pelarian . Begitu banyak operator regexp (^\|$
) memiliki makna tersendiri di shell.Shell Thompson mengandalkan utilitas eksternal untuk globbing. Ketika
sh
ditemukan tanda kutip*
,[
atau?
s dalam perintah, itu akan menjalankan perintahglob
.akan berakhir menjalankan glob sebagai:
dan glob akan berakhir berjalan
rm
dengan daftar file yang cocok dengan pola itu.akan berjalan
glob
sebagai:Di
*
atas telah dikutip dengan menetapkan bit ke-8 pada karakter itu, mencegahglob
memperlakukannya sebagai wildcard.glob
kemudian akan menghapus bit itu sebelum memanggilgrep
.Untuk melakukan hal yang sama dengan regexps, itu seharusnya:
Atau:
untuk mengecualikan file-file dot.
Kebutuhan untuk melarikan diri dari operator karena mereka menggandakan sebagai karakter khusus shell, fakta bahwa
.
, umum dalam nama file adalah operator regexp membuatnya sangat tidak sesuai untuk mencocokkan nama file dan rumit untuk pemula. Dalam kebanyakan kasus, semua yang Anda butuhkan adalah wildcard yang dapat menggantikan satu (?
) atau nomor (*
) karakter apa pun.Sekarang, cangkang yang berbeda menambahkan operator globbing yang berbeda. Saat ini, ksh dan zsh gumpalan (dan sampai batas tertentu
bash -O extglob
yang mengimplementasikan himpunan bagian dari gumpalan ksh) secara fungsional setara dengan regexps dengan sintaks yang kurang rumit untuk digunakan dengan nama file dan sintaksis shell saat ini. Misalnya, dalamzsh
(dengan ekstensi extendedglob), Anda dapat melakukan:jika Anda ingin (tidak mungkin) mencocokkan nama file yang terdiri dari urutan
a
diikuti oleh.txt
. Lebih mudah daripadaecho (^a*\.txt$)
(di sini menggunakan kawat gigi sebagai cara untuk mengisolasi operator regex dari operator shell yang bisa menjadi salah satu cara shell bisa mengatasinya).Untuk file mpg (tidak sensitif huruf besar) yang nama dasarnya adalah foo, bar atau angka desimal dari 1 hingga 20 ...
ksh93
sekarang juga dapat memasukkan regexps (dasar, diperpanjang, perl-like atau "augmented") dalam gumpalannya (meskipun cukup buggy) dan bahkan menyediakan alat untuk mengkonversi antara glob dan regexp (printf %R
,printf %P
):untuk mencocokkan file-file txt (non-tersembunyi) dengan E- xtended regular expressions, case- i nsensitive.
sumber
~(opt:pat)
untuk salah satu opsi huruf besar. Mungkinprint -r -- ~(Ei).*\.txt$
. Menempatkan pola di dalamnya tampaknya hanya berguna untuk menghindari keharusan beralih opsi lalu mematikan untuk bagian dari pola. Anehnya, Anda dapat mencampur-dan-mencocokkan beberapa bahasa pola dalam glob yang sama.~(Ki)*.~(E)txt$
setara. (Pada akhirnya semuanya baru saja dikonversi menjadi regex dan diteruskan ke mesin regex libast secara internal).~(Ei:.*\.txt)
bekerja untuk saya bahkan dengan versi 15 tahun seperti ksh93 o +.~(E)x
dan~(E:x)
adalah bahwa yang terakhir berlabuh (cocokx
hanya saat yang pertama cocok dengan apa pun yang mengandungx
), yang mungkin merupakan jenis masalah yang Anda temui (gunakan~(-lr)~(E:x)
untuk menghapus jangkar,~(E-lr:x)
tidak akan dilakukan). Bagaimanapun, saya setuju itu cukup buggy, bahkan dalam versi terbaru.Bahasa reguler diperkenalkan oleh Kleene pada tahun 1956. Makalah seminalis tidak memiliki notasi modern penuh untuk ekspresi reguler, tetapi itu memperkenalkan "bintang Kleen": yang
A*
berarti "sejumlah pengulanganA
". Pada dekade berikutnya, beberapa notasi standar lebih atau kurang muncul, khususnya.
untuk karakter sewenang-wenang dan?
berarti bahwa karakter sebelumnya adalah opsional.Notasi Bash globbing berasal dari
glob
perintah yang diperkenalkan sepanjang jalan kembali ke Unix v1 pada tahun 1971. Pada saat itu, globbing dilakukan oleh program terpisah; kemudian dipindahkan ke shell.glob
Perintah awal?
harus berarti "karakter apa saja" dan*
berarti "urutan karakter apa saja". Saya tidak tahu mengapa karakter dipilih;?
cukup intuitif, dan*
mungkin terinspirasi dari ekspresi reguler.Globbing tidak dimaksudkan untuk menjadi umum seperti ekspresi reguler, dan ekspresi reguler tidak terlalu luas pada saat itu, jadi tidak ada panggilan untuk menyatukan konsep. Sejak awal, ada ketidaksesuaian sintaksis, dengan
?
,.
dan*
memaknai hal-hal yang berbeda dalam pola nama file dan dalam ekspresi reguler.Kerang modern seperti bash berkembang pada pola gumpalan, tapi itu adalah evolusi bertahap yang menjaga kompatibilitas ke belakang. Ksh88 (versi 1988 dari shell Korn ) memperkenalkan sintaksis diperpanjang untuk pola shell, yang tidak mungkin sintaksis yang sama seperti ekspresi reguler biasa tetapi sangat terinspirasi olehnya:
*(PATTERN)
berarti sejumlah pengulanganPATTERN
,@(PATTERN1|PATTERN2)
berarti "PATTERN1
atauPATTERN2
", dll.Versi modern dari bash (sejak 2.02) mendukung pola ksh88 yang diperluas, jika Anda menerbitkannya
shopt -s extglob
terlebih dahulu.sumber
extglob
opsi diperkenalkan di bash 2.02 di suatu tempat sekitar tahun 1998. Zsh diperolehksh_glob
dalam seri 3.1 di suatu tempat di sekitar waktu yang sama. Zsh memiliki banyak ekstensi globbing sendiri (beberapa memerlukanextended_glob
opsi).bash
sebaliknyaksh
, extglob membuat bash non-POSIX compliant karena tidak dinonaktifkan dalam variabel. Dalamksh
,var='@(*)'; echo $var
memperluas ke semua nama file dalam direktori saat ini yang dimulai dengan@(
dan diakhiri)
sebagai POSIX membutuhkan sementara dibash -O extglob
dalamnya memperluas ke semua file. (masih, orang mungkin menganggap perilaku bash lebih masuk akal di sini (dan perilaku ksh cukup menyebalkan ketika Anda ingin memiliki pola dalam variabel)). Sintaks glob sangat canggung karena itu (kompatibilitas POSIX / Bourne). Bandingkan dengan zsh extended globs.Alasan historis: YA. Referensi:
http://en.wikipedia.org/wiki/Glob_(programming)#Origin
Hanya untuk menunjukkan perbedaan, berikut adalah contoh yang bagus dan mudah:
a*
a
dan kemudian apapun (a, ab, abca ...)a
(a, aa, aaa ...)Saya siap setuju bahwa perbedaan makna ini sangat membingungkan bagi pengguna baru.
Globbing mungkin lebih mudah dipahami oleh pendatang baru, tetapi juga konstruksi yang kurang kuat.
sumber