Asumsikan direktori memiliki 100 file dimulai dengan huruf 'a'.
Jika saya melakukan grep <some string> a*
dari terminal, bagaimana shell menangani ini?
Apakah ini akan memperluas ekspresi reguler, mendapatkan daftar semua file dimulai dengan a dan grep pada masing-masing file secara berurutan? Atau ada cara lain?
Asumsikan bahwa saya memiliki array nama file di atas yang dimulai dengan 'a'. Apakah akan memakan waktu lebih banyak / lebih sedikit jika saya menulis loop for dan melakukan iterasi sendiri dalam skrip shell atau program ac?
glob
bukan ekspresi reguler. Perbedaan besar.Jawaban:
Pertama, nitpick: string seperti
a*
pada sintaksis shell normal adalah gumpalan, yang bekerja secara berbeda dari ekspresi reguler.Pada ikhtisar tingkat tinggi, shell interpreter (yaitu bash) memperluas string
a*
ke daftar setiap nama file yang cocok dengan polaa*
. Ini kemudian menjadi bagian dari parameter baris perintah ke satu instancegrep
(untuk programmer, semua kata yang diperluas pergi sebagai string terpisah ke dalamargv
argumenmain
).grep
Perintah tunggal itu kemudian mem-parsing argumen dengan cara apa pun yang dipilihnya, dan terserah untukgrep
menafsirkan argumen tersebut sebagai nama file, opsi, argumen opsi, ekspresi reguler, dll., Dan mengambil tindakan yang sesuai. Semuanya terjadi secara berurutan (AFAIK tidak adagrep
implementasi menggunakan beberapa utas).Jika Anda menerapkan loop dalam skrip shell untuk melakukan hal yang sama, itu hampir pasti lebih lambat dari proses di atas, karena alasan berikut. Jika Anda menelurkan proses grep baru untuk setiap file, itu pasti akan lebih lambat karena overhead pembuatan proses dikalikan tidak perlu. Jika Anda membuat daftar argumen sendiri di skrip shell dan menggunakan satu contoh
grep
, apa pun yang Anda lakukan di shell masih akan lebih lambat karena perintah shell harus ditafsirkan (dengan bash), yang menambahkan lapisan kode tambahan, dan Anda akan hanya akan mengimplementasikan kembali apa yang sudah dilakukan bash lebih cepat secara internal dalam kode yang dikompilasi.Sedangkan untuk menuliskannya sendiri dalam C, Anda mungkin dapat dengan mudah mendapatkan kinerja yang sebanding dengan proses yang dijelaskan dalam paragraf pertama, tetapi tidak mungkin Anda akan dapat mencapai cukup dari peningkatan kinerja dibandingkan implementasi grep / bash saat ini untuk membenarkan waktu. dihabiskan tanpa mempelajari optimalisasi kinerja khusus mesin atau mengorbankan portabilitas. Mungkin Anda bisa mencoba membuat versi yang dapat diparalelkan secara sewenang-wenang
grep
, tetapi bahkan itu mungkin tidak membantu karena Anda lebih cenderung terikat I / O daripada terikat CPU. Ekspansi dan grep global sudah "cukup cepat" untuk sebagian besar tujuan "normal".sumber
zcat
danzgrep
; tidak perlu mendekompres mereka satu per satuYa, itu akan berkembang ke daftar file dan mengumpankan daftar yang dihasilkan ke
grep
program. Setidaknya itulah yangman bash
dikatakan di dalam bagian Perluasan Pathname .Ada cara lain untuk menggunakan ekspansi dalam kasus sederhana seperti yang Anda sebutkan: tulis
grep <some_string> a
dan sebelum menekan*
, tekan ESC. Ini akan memperluas daftar file yang cocok tepat di baris perintah, sehingga Anda dapat memverifikasi daftar itu OK sebelum menekan Enter.Adapun bagian kedua dari pertanyaan Anda, itu tergantung. Jika Anda bermaksud menulis for-loop yang menjalankan grep pada setiap file secara bergantian, maka itu pasti akan lebih lambat, karena program grep akan dijalankan tidak hanya sekali, tetapi sekali per file. Namun, apa yang penting untuk diingat adalah bahwa ada tertentu batas pada panjang diperluas argumen baris perintah yang dapat Anda gunakan, meskipun biasanya cukup tinggi. Untuk melihatnya, Anda bisa mencoba
grep adasdsadf /usr/*/*/* >/dev/null
.sumber
ESC+*
tidak persis sama dengan membiarkan bash diperluas * karenaESC+*
akan memasukkan dotfile (nama yang dimulai dengan a.
) sedangkan perluasan*
tergantung padadotglob
shopt
pengaturan. Urutan kunci untuk memperluas dan memasukkan gumpalan adalahC-x *
secara default dan memetakan ke perintah readlineglob-expand-word
.a*
ekspansi, tetapi tentu saja penting dalam lingkup yang lebih luas.zsh
Catatan: cukup menekan tombol tab pada parameter yang dapat diperluas (pola glob, brace-expansion, command-substitution, ...) akan memperluasnya.C-x
pintasan dan tidak memperluas daftar file di sistem saya (menggunakan bash).C-x *
hanya melakukan gumpalan yang hanya melakukan nama file, tetapiEsc *
sebenarnya melakukan lebih banyak karena ituinsert-completions
, seperti dalam semua penyelesaian yang mungkin. Ini berarti menggunakanEsc *
pada baris perintah kosong akan memasukkan nama setiap file yang dapat dieksekusi di Anda$PATH
, misalnya.