Aku tahu **/*.extmengembang ke semua file dalam semua subdirektori yang cocok *.ext, tapi apa adalah ekspansi yang sama yang mencakup semua file tersebut di saat direktori juga?
Jawaban:
Ini akan bekerja di Bash 4:
ls -l {,**/}*.ext
Agar globe tanda bintang ganda bekerja, globstaropsi perlu disetel (default: aktif):
shopt -s globstar
Dari man bash:
globstar
Jika disetel, pola ** yang digunakan dalam konteks perluasan nama file
teks akan cocok dengan file dan nol atau lebih direktori dan
subdirektori. Jika polanya hanya diikuti oleh a /, saja
direktori dan subdirektori cocok.
Sekarang saya bertanya-tanya apakah mungkin pernah ada bug dalam pemrosesan globstar, karena sekarang dengan hanya menggunakan ls **/*.extsaya mendapatkan hasil yang benar.
Terlepas dari itu, saya melihat analisis yang dilakukan kenorb menggunakan repositori VLC dan menemukan beberapa masalah dengan analisis itu dan dalam jawaban saya tepat di atas:
Perbandingan dengan keluaran findperintah tidak valid karena menentukan -type ftidak menyertakan jenis file lain (khususnya direktori) dan lsperintah yang terdaftar kemungkinan besar melakukannya. Juga, salah satu perintah yang terdaftar, ls -1 {,**/}*.*- yang tampaknya didasarkan pada milik saya di atas, hanya mengeluarkan nama yang menyertakan titik untuk file-file yang ada di subdirektori. Pertanyaan OP dan jawaban saya menyertakan titik karena yang dicari adalah file dengan ekstensi tertentu.
Yang paling penting, bagaimanapun, adalah bahwa ada masalah khusus dalam menggunakan lsperintah dengan pola globstar **. Banyak duplikat muncul karena pola tersebut diperluas oleh Bash ke semua nama file (dan nama direktori) di pohon yang sedang diperiksa. Setelah perluasan, lsperintah mencantumkan masing - masing dan kontennya jika berupa direktori.
Contoh:
Di direktori kami saat ini adalah subdirektori Adan isinya:
A
└── AB
└── ABC
├── ABC1
├── ABC2
└── ABCD
└── ABCD1
Di pohon itu, **diperluas menjadi "AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1" (7 entri) . Jika Anda melakukan echo **itu, hasil yang tepat akan Anda dapatkan dan setiap entri diwakili satu kali. Namun , jika Anda melakukannya, ls **itu akan menghasilkan daftar dari masing - masing entri tersebut. Jadi pada dasarnya itu ls Adiikuti oleh ls A/AB, dll., Jadi A/ABakan ditampilkan dua kali. Juga, lsakan memisahkan keluaran setiap subdirektori:
...
<blank line>
directory name:
content-item
content-item
Jadi menggunakan wc -lmenghitung semua baris kosong dan judul bagian nama direktori yang membuang hitungan lebih jauh.
Ini adalah alasan lain mengapa Anda tidak perlu mengurails .
Sebagai hasil dari analisis lebih lanjut ini, saya menyarankan untuk tidak menggunakan pola globstar dalam keadaan apa pun selain melakukan iterasi pada pohon file dengan cara ini:
for entry in **
do
something "$entry"
done
Sebagai perbandingan terakhir, saya menggunakan repositori sumber Bash yang saya miliki dan melakukan ini:
shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .
Saya biasa trmengubah spasi ke baris baru yang hanya berlaku di sini karena tidak ada nama yang menyertakan spasi. Saya biasa sedmenghapus garis depan ./dari setiap baris keluaran find. Saya mengurutkan output findkarena biasanya tidak disortir dan perluasan gumpalan Bash sudah diurutkan. Seperti yang Anda lihat, satu-satunya keluaran dari diffadalah .keluaran direktori saat ini oleh find. Ketika saya melakukannya ls ** | wc -l, hasilnya hampir dua kali lebih banyak baris.
globstardefaultoff
**/*.extseharusnya sudah cukup. Selain itu, Anda tidak akan memiliki file tersembunyi kecuali Anda shopt -s dotglob.
globstar: shopt -u globstar.
**/*.exttidak akan cukup
Ini akan mencetak semua file di direktori saat ini dan subdirektorinya yang diakhiri dengan '.ext'.
find . -name '*.ext' -print
Anda dapat menggunakan: **/*.*untuk memasukkan semua file secara rekursif (diaktifkan oleh:) shopt -s globstar.
Silakan temukan di bawah pengujian variasi lain dan bagaimana perilakunya.
Menguji folder dengan 3472 file di folder repositori VLC sampel :
(Total file dari 3472 dihitung sebagai per: find . -type f | wc -l)
ls -1 **/*.* - mengembalikan 3338ls -1 {,**/}*.*- mengembalikan 3341 (seperti yang diusulkan oleh Dennis )ls -1 {,**/}* - mengembalikan 8265ls -1 **/*- mengembalikan 7817, kecuali file tersembunyi (seperti yang diusulkan oleh Dennis )ls -1 **/{.[^.],}*- mengembalikan 7869 (seperti yang diusulkan oleh Dennis )ls -1 {,**/}.?* - mengembalikan 15855ls -1 {,**/}.* - mengembalikan 20321Jadi saya pikir metode paling dekat untuk mendaftar semua file secara rekursif adalah contoh pertama ( **/*.*) sesuai komentar gniourf-gniourf (dengan asumsi file memiliki ekstensi yang tepat, atau gunakan yang spesifik), karena contoh kedua memberikan beberapa duplikat lagi seperti di bawah ini :
$ diff -u <(ls -1 {,**/}*.*) <(ls -1 **/*.*)
--- /dev/fd/63 2015-04-19 15:25:07.000000000 +0100
+++ /dev/fd/62 2015-04-19 15:25:07.000000000 +0100
@@ -1,6 +1,4 @@
COPYING.LIB
-COPYING.LIB
-Makefile.am
Makefile.am
@@ -45,7 +43,6 @@
compat/tdestroy.c
compat/vasprintf.c
configure.ac
-configure.ac
dan yang lainnya menghasilkan duplikat lebih lanjut.
Untuk menyertakan file tersembunyi, gunakan: shopt -s dotglob(nonaktifkan oleh shopt -u dotglob). Ini tidak disarankan, karena dapat mempengaruhi perintah seperti mvatau rmdan Anda dapat menghapus file yang salah secara tidak sengaja.
**/*.*) informatif dan bekerja paling baik. Jawaban yang diterima menyebabkan duplikat item di direktori teratas. Pola kerja saya adalah:"${path}"**/*.*
$ find . -type f
Itu akan mencantumkan semua file di direktori saat ini. Anda kemudian dapat melakukan beberapa perintah lain pada keluaran menggunakan -exec
$find . -type f -exec grep "foo" {} \;
Itu akan menggrep setiap file dari pencarian untuk string "foo".
find . -type fberlaku secara rekursif dengan root di direktori saat ini, tidak hanya ke direktori saat ini.
Mengapa tidak menggunakan perluasan brace untuk menyertakan direktori saat ini juga?
./{*,**/*}.ext
Ekspansi brace terjadi sebelum ekspansi glob, sehingga Anda dapat secara efektif melakukan apa yang Anda inginkan dengan versi bash yang lebih lama, dan dapat mengabaikan penggunaan globstar di versi yang lebih baru.
Selain itu, dianggap praktik yang baik dalam bash untuk memasukkan yang terdepan ./dalam pola glob Anda.
**/*.ext. Apakah Anda yakin itu berhasil untuk Anda?