Apakah ada perintah bash yang menghitung jumlah file yang cocok dengan suatu pola?
Sebagai contoh, saya ingin mendapatkan jumlah semua file dalam direktori yang cocok dengan pola ini: log*
Satu kalimat sederhana ini harus bekerja di shell apa pun, bukan hanya bash:
ls -1q log* | wc -l
ls -1q akan memberi Anda satu baris per file, meskipun mengandung spasi atau karakter khusus seperti baris baru.
Outputnya disalurkan ke wc -l, yang menghitung jumlah baris.
-l
, karena itu memerlukanstat(2)
pada setiap file dan untuk tujuan penghitungan menambahkan apa-apa.ls
, karena itu menciptakan proses anak.log*
diperluas oleh shell, tidakls
, jadi sederhanaecho
akan dilakukan.logs
dalam direktori yang dimaksud, maka isi dari direktori log tersebut akan dihitung juga. Ini mungkin tidak disengaja.Anda dapat melakukan ini dengan aman (mis. Tidak akan disadap oleh file dengan spasi atau
\n
namanya) dengan bash:Anda perlu mengaktifkan
nullglob
sehingga Anda tidak mendapatkan literal*.log
dalam$logfiles
array jika tidak ada file yang cocok. (Lihat Bagaimana "membatalkan" 'set -x'? Untuk contoh cara meresetnya dengan aman.)sumber
shopt -u nullglob
harus dilewati jikanullglob
tidak disetel maka Anda mulai.*.log
dengan hanya*
akan menghitung direktori. Jika file yang ingin Anda hitung memiliki konvensi penamaan tradisionalname.extension
, gunakan*.*
.Banyak jawaban di sini, tetapi beberapa tidak memperhitungkan
-l
)*.log
bukanlog*
logs
yang cocoklog*
)Inilah solusi yang menangani semuanya:
Penjelasan:
-U
menyebabkanls
untuk tidak mengurutkan entri, artinya tidak perlu memuat seluruh daftar direktori dalam memori-b
mencetak gaya-C yang keluar untuk karakter nongrafik, yang paling penting menyebabkan baris baru dicetak sebagai\n
.-a
mencetak semua file, bahkan file yang tersembunyi (tidak sepenuhnya dibutuhkan ketika globlog*
tidak mengandung file tersembunyi)-d
mencetak direktori tanpa berusaha membuat daftar isi direktori, yangls
biasanya akan dilakukan-1
memastikan bahwa itu ada di satu kolom (ls melakukan ini secara otomatis saat menulis ke pipa, sehingga tidak sepenuhnya diperlukan)2>/dev/null
mengarahkan ulang stderr sehingga jika ada 0 file log, abaikan pesan kesalahan. (Catatan yangshopt -s nullglob
akan menyebabkanls
daftar seluruh direktori kerja sebagai gantinya.)wc -l
mengkonsumsi daftar direktori seperti yang dihasilkan, jadi output darils
tidak pernah ada dalam memori kapan saja.--
Nama file dipisahkan dari perintah menggunakan--
agar tidak dipahami sebagai argumen untukls
(jikalog*
dihapus)Shell akan diperluas
log*
ke daftar lengkap file, yang dapat menghabiskan memori jika banyak file, jadi menjalankannya melalui grep lebih baik:Yang terakhir ini menangani direktori file yang sangat besar tanpa menggunakan banyak memori (meskipun menggunakan subkulit). Tidak
-d
lagi diperlukan, karena itu hanya daftar isi direktori saat ini.sumber
Untuk pencarian rekursif:
wc -c
akan menghitung jumlah karakter dalam outputfind
, sementara-printf x
memberitahufind
untuk mencetak satux
untuk setiap hasil.Untuk pencarian non-rekursif, lakukan ini:
sumber
-name '*.log'
begitu saja maka itu akan menghitung semua file, yang saya butuhkan untuk kasus penggunaan saya. Bendera -maxdepth juga sangat berguna, terima kasih!find
; hanya mencetak sesuatu yang lain dari nama file kata demi kata.Jawaban yang diterima untuk pertanyaan ini salah, tetapi saya memiliki rep rendah sehingga tidak dapat menambahkan komentar untuk itu.
Jawaban yang benar untuk pertanyaan ini diberikan oleh Mat:
Masalah dengan jawaban yang diterima adalah bahwa wc-l menghitung jumlah karakter baris baru, dan menghitungnya bahkan jika mereka mencetak ke terminal sebagai '?' dalam output 'ls-l'. Ini berarti bahwa jawaban yang diterima GAGAL ketika nama file berisi karakter baris baru. Saya telah menguji perintah yang disarankan:
dan secara keliru melaporkan nilai 2 bahkan jika hanya ada 1 file yang cocok dengan pola yang namanya mengandung karakter baris baru. Sebagai contoh:
sumber
Jika Anda memiliki banyak file dan Anda tidak ingin menggunakan
shopt -s nullglob
solusi array elegan dan bash, Anda dapat menggunakan find dan sebagainya selama Anda tidak mencetak nama file (yang mungkin berisi baris baru).Ini akan menemukan semua file yang cocok dengan log * dan yang tidak dimulai dengan
.*
- "not name. *" Redunant, tetapi penting untuk dicatat bahwa default untuk "ls" adalah tidak menampilkan file-file dot, tetapi default untuk menemukan adalah memasukkan mereka.Ini adalah jawaban yang benar, dan menangani semua jenis nama file yang dapat Anda berikan padanya, karena nama file tidak pernah berpindah antar perintah.
Tapi,
shopt nullglob
jawabannya adalah jawaban terbaik!sumber
find
vs menggunakanls
adalah dua cara berbeda untuk menyelesaikan masalah.find
tidak selalu hadir pada mesin, tetapils
biasanya,find
mungkin tidak memiliki semua opsi mewah untukls
keduanya.-maxdepth 1
find
melakukan ini secara default. Ini dapat membuat kebingungan jika seseorang tidak menyadari ada folder anak tersembunyi, dan mungkin membuatnya menguntungkan untuk digunakanls
dalam beberapa keadaan, yang tidak melaporkan file tersembunyi secara default.Ini satu liner saya untuk ini.
sumber
set --
tidak melakukan apa pun kecuali menyiapkan kita$#
, yang menyimpan sejumlah argumen baris perintah yang diteruskan ke program shellAnda dapat menggunakan opsi -R untuk menemukan file bersama dengan yang ada di dalam direktori rekursif
Anda dapat menggunakan pola pada grep
sumber
Komentar penting
(tidak cukup reputasi untuk berkomentar)
Ini BUGGY :
Jika
shopt -s nullglob
kebetulan diatur, itu mencetak jumlah SEMUA file biasa, bukan hanya yang dengan pola (diuji pada CentOS-8 dan Cygwin). Siapa yang tahu apa yang dilakukan bug tidak berarti lainnyals
dimiliki ?Ini BENAR dan jauh lebih cepat:
Itu melakukan pekerjaan yang diharapkan.
Dan waktu berlari berbeda.
Yang pertama:
0.006
pada CentOS, dan0.083
pada Cygwin (kalau-kalau digunakan dengan hati-hati).Yang ke-2:
0.000
di CentOS, dan0.003
di Cygwin.sumber
Anda dapat mendefinisikan perintah seperti itu dengan mudah, menggunakan fungsi shell. Metode ini tidak memerlukan program eksternal dan tidak menelurkan proses anak. Itu tidak mencoba
ls
parsing berbahaya dan menangani karakter "khusus" (spasi putih, baris baru, garis miring terbalik dan sebagainya) baik-baik saja. Itu hanya bergantung pada mekanisme ekspansi nama file yang disediakan oleh shell. Ini kompatibel dengan setidaknya sh, bash, dan zsh.Baris di bawah ini mendefinisikan fungsi yang disebut
count
yang mencetak jumlah argumen yang telah dipanggil.Sebut saja dengan pola yang diinginkan:
Agar hasilnya benar ketika pola globbing tidak cocok, opsi shell
nullglob
(ataufailglob
- yang merupakan perilaku default pada zsh) harus ditetapkan pada saat ekspansi terjadi. Dapat diatur seperti ini:Bergantung pada apa yang ingin Anda hitung, Anda mungkin juga tertarik dengan opsi shell
dotglob
.Sayangnya, dengan bash setidaknya, tidak mudah untuk mengatur opsi ini secara lokal. Jika Anda tidak ingin mengaturnya secara global, solusi paling mudah adalah menggunakan fungsi ini dengan cara yang lebih berbelit-belit:
Jika Anda ingin memulihkan sintaks yang ringan
count log*
, atau jika Anda benar-benar ingin menghindari memunculkan subkulit, Anda dapat meretas sesuatu di sepanjang baris:Sebagai bonus, fungsi ini lebih umum digunakan. Misalnya:
Dengan mengubah fungsi menjadi file skrip (atau program C yang setara), dapat dipanggil dari PATH, ia juga dapat dibuat dengan program-program seperti
find
danxargs
:sumber
Saya telah memberikan jawaban ini banyak pemikiran, terutama mengingat hal -hal yang jangan diurai . Pada awalnya, saya mencoba
yang bekerja jika hanya ada nama file seperti
tetapi gagal jika saya membuat nama file seperti ini
Saya akhirnya menemukan apa yang saya tuliskan di bawah. Catatan saya mencoba untuk mendapatkan hitungan semua file dalam direktori (tidak termasuk subdirektori). Saya pikir itu, bersama dengan jawaban oleh @Mat dan @Dan_Yard, serta memiliki setidaknya sebagian besar persyaratan yang ditetapkan oleh @mogsie (saya tidak yakin tentang memori.) Saya pikir jawabannya oleh @mogsie sudah benar, tetapi saya selalu berusaha untuk tidak menguraikan
ls
kecuali itu situasi yang sangat spesifik.Lebih mudah dibaca:
Ini melakukan pencarian khusus untuk file, membatasi output dengan karakter nol (untuk menghindari masalah dengan spasi dan linefeeds), lalu menghitung jumlah karakter nol. Jumlah file akan menjadi kurang dari jumlah karakter nol, karena akan ada karakter nol di akhir.
Untuk menjawab pertanyaan OP, ada dua hal yang perlu dipertimbangkan
1) Pencarian non-rekursif:
2) Pencarian rekursif. Perhatikan bahwa apa yang ada di dalam
-name
parameter mungkin perlu diubah untuk perilaku yang sedikit berbeda (file tersembunyi, dll.).Jika ada yang ingin mengomentari bagaimana jawaban ini dibandingkan dengan yang saya sebutkan dalam jawaban ini, silakan lakukan.
Catatan, saya sampai pada proses pemikiran ini sambil mendapatkan jawaban ini .
sumber
Inilah yang selalu saya lakukan:
sumber
awk 'END{print NR}'
harus setara denganwc -l
.Yang berarti daftar satu file per baris dan kemudian pipa ke perintah jumlah kata dengan pergantian parameter untuk menghitung baris.
sumber
Untuk menghitung semuanya, pipa saja ke baris hitung kata:
Untuk menghitung dengan pola, pipa untuk menerima terlebih dahulu:
sumber