Apakah ada sesuatu yang lebih cepat daripada `find. | wc -l` untuk menghitung file dalam direktori?

8

Tidak jarang saya harus menghitung jumlah file dalam suatu direktori, terkadang ini mencapai jutaan.

Apakah ada cara yang lebih baik dari sekadar menghitung dan menghitungnya find . | wc -l? Apakah ada semacam panggilan filesystem yang dapat Anda lakukan pada ext3 / 4 yang kurang I / O intensif?

MattPark
sumber
3
Anda tidak hanya menghitung file, tetapi juga direktori. Jika Anda hanya ingin menghitung file, gunakan "find. -Type f | wc -l" jika Anda ingin menghitung tautan simbolis dan file biasa, gunakan "find. -Type f -atau -tipe l | wc -l"
FSMaxB
Direktori adalah sejenis file, seperti halnya perangkat, symlink dan soket. File biasa adalah bagian dari file.
Toby Speight
1
Contoh yang Anda berikan menunjukkan bahwa Anda menginginkan hitungan rekursif - jika tidak, maka Anda perlu find -maxdepth 1. Perhatikan bahwa dengan pendekatan Anda saat ini, Anda akan menghitung ulang nama apa pun yang berisi karakter baris baru.
Toby Speight

Jawaban:

13

Bukan kecepatan dasar tetapi setidaknya sesuatu :)

find . -printf \\n | wc -l

Anda benar-benar tidak perlu melewati daftar nama file, cukup baris baru saja. Varian ini sekitar 15% lebih cepat pada Ubuntu 12.04.3 saya ketika direktori di-cache dalam RAM. Selain itu varian ini akan berfungsi dengan benar dengan nama file yang mengandung baris baru.

Menariknya varian ini tampaknya sedikit lebih lambat daripada yang di atas:

find . -printf x | wc -c

Kasus khusus - tetapi sangat cepat

Jika direktori berada pada sistem file sendiri, Anda dapat menghitung inode:

df -i .

Jika jumlah direktori dan file di direktori lain dari yang dihitung tidak banyak berubah, Anda cukup mengurangi angka yang diketahui ini dari df -ihasil saat ini . Dengan cara ini Anda akan dapat menghitung file dan direktori dengan sangat cepat.

pabouk
sumber
"Varian ini sekitar 15% lebih cepat ..." membuat saya bertanya-tanya apakah ada semacam trik berguna yang Anda gunakan untuk mengatur waktu ini?
Brian Z
4
@BrianZ: Anda dapat mengatur waktu perintah dengan menambahkan perintah pada waktu. time find /usr/src/ -printf \\n | wc -l, Anda dapat menghapus cache di sela-sela run dengansudo sync && sudo sysctl -w vm.drop_caches=3
MattPark
Jadi saya melihat peningkatan 2% yang konsisten dalam kecepatan dengan salah satu dari 2 opsi pertama tanpa caching. Jadi ya itu cara yang cukup keren untuk melakukannya. Menghitung inode jelas yang terbaik jika lingkungan Anda diatur untuk itu. Saya belum mempertimbangkannya.
MattPark
Apakah -printf xharus sama dengan -printf '\0'? Saya tidak melihatnya disebutkan dalam dokumen.
CMCDragonkai
@ CMCDragonkai: Tindakan ini -printfbekerja mirip dengan printf()fungsi dalam C dengan perbedaan utama bahwa %arahan memiliki makna yang berbeda. Tindakan ini dipanggil untuk setiap file yang ditemukan. Ini berarti bahwa -printf xakan mencetak karakter xuntuk setiap file yang ditemukan (coba saja!) Dan -printf '\0'akan mencetak karakter NULL (kode ASCII 0) untuk setiap file yang ditemukan. -printf '\0'tidak memiliki arti khusus. Keduanya akan bekerja sama dalam contoh dengan wc -cjawaban ini.
pabouk
3

Saya telah menulis ffcnt untuk tujuan itu. Ia mengambil offset fisik direktori itu sendiri dengan fiemapioctl dan kemudian menjadwalkan direktori traversal dalam beberapa urutan berurutan untuk mengurangi akses acak. Apakah Anda benar-benar mendapatkan speedup dibandingkan dengan find | wc tergantung pada beberapa faktor:

  • tipe filesystem: filesystem seperti ext4 yang mendukung fiemapioctl akan mendapat manfaat paling besar
  • kecepatan akses acak: HDD lebih diuntungkan daripada SSD
  • tata letak direktori: semakin tinggi jumlah direktori bersarang, semakin banyak potensi optimisasi

(re) pemasangan dengan relatimeatau bahkan nodiratimejuga dapat meningkatkan kecepatan (untuk semua metode) ketika akses sebaliknya akan menyebabkan pembaruan metadata.

the8472
sumber
Kalimat terakhir itu adalah tip yang bermanfaat! Saya pikir tautan ke program Anda akan ditingkatkan jika Anda menambahkan ringkasan tentang cara kerjanya. Kami lebih suka jawaban yang lengkap dalam dirinya sendiri, kalau-kalau ada hal buruk terjadi pada sumber daya terkait (tapi tentu saja menjaga tautannya).
Toby Speight
2

Sebenarnya, pada sistem saya (Arch Linux) perintah ini

   ls -A | wc -l

lebih cepat dari semua yang di atas:

   $ time find . | wc -l
  1893

   real    0m0.027s
   user    0m0.004s
   sys     0m0.004s
   $ time find . -printf \\n  | wc -l
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time find . -printf x  | wc -c
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time ls -A | wc -l
   1892

   real    0m0.007s
   user    0m0.000s
   sys     0m0.004s
MariusMatutiae
sumber
Saya pikir masalah dengan ls adalah bahwa ia sering mengembalikan sesuatu seperti /bin/ls: Argument list too longjika Anda menggunakan globbing, tetapi sekali lagi ia dapat beroperasi secara rekursif seperti menemukan juga, jadi mungkin itu adalah sesuatu yang perlu dipertimbangkan, jangan gunakan menemukan jika tidak diperlukan.
MattPark
Tampaknya sangat terlambat (bertahun-tahun) untuk berkomentar tentang itu, tetapi ls -Ahanya daftar file dalam direktori saat ini sementara findtanpa -maxdepth 1argumen akan membuat pencarian rekursif melalui semua subdirektori.
Luciano