Bagaimana cara menghitung jumlah file di setiap direktori?

105

Saya dapat membuat daftar semua direktori dengan

find ./ -type d

Saya mencoba membuat daftar isi setiap direktori dan menghitung jumlah file di setiap direktori dengan menggunakan perintah berikut

find ./ -type d | xargs ls -l | wc -l

Tapi ini menjumlahkan jumlah baris yang dikembalikan

find ./ -type d | xargs ls -l

Adakah cara untuk menghitung jumlah file di setiap direktori?

pengguna784637
sumber
Apakah Anda mencari cara untuk menghitung jumlah file di setiap sub-direktori langsung di bawah ./?
Tuxdude
5
Bagaimana ini pertanyaan di luar topik ?? Saya ingin melihat komentar pemilih-dekat dengan alasan! Jika ini di luar topik, lalu di manakah ini? pengguna super? Kurasa tidak ..
InfantPro'Aravind '
6
shell-script, batch-script berada di bawah lingkup pemrograman!
InfantPro'Aravind '
Saya akan memposting solusi Pythonic kemudian saya perhatikan bahwa pertanyaannya sudah ditutup.
anatoly techtonik
memilih untuk membukanya kembali. Mungkin ada jawaban lain yang dapat berguna dalam banyak situasi (termasuk pemrograman skrip, yang menjadi alasan saya mencapai pertanyaan ini).
lepe

Jawaban:

110

Dengan asumsi Anda memiliki GNU find, biarkan ia menemukan direktori dan biarkan bash melakukan sisanya:

find . -type d -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done
glenn jackman
sumber
2
Ini hanya versi yang sedikit berbeda dari yang di atas, jadi: (petunjuk: diurutkan berdasarkan nama dan di csv) untuk x in find . -maxdepth 1 -type d | sort; apakah y = find $x | wc -l; echo $ x, $ y; selesai
pcarvalho
5
Bagus! Menempatkannya ke dalam satu baris (sehingga nyaman untuk penggunaan langsung di shell):find . -type d -print0 | while read -d '' -r dir; do files=("$dir"/*); printf "%5d files in directory %s\n" "${#files[@]}" "$dir"; done
lucaferrario
13
Saya perlu mendapatkan jumlah semua file (dihitung secara rekursif) di setiap subdirektori. Modifikasi ini memberi Anda bahwa: find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find $dir -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
OmidS
1
@Kory Berikut ini akan melakukannya:find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done | sort -rn -k1
OmidS
1
@OmidS Satu kata yang bagus, tapi $dirharus di dalam tanda kutip di komentar pertama Anda untuk menangani nama dir dengan spasi putih dengan benar. :find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
Radek Daniluk
183

Ini mencetak jumlah file per direktori untuk tingkat direktori saat ini:

du -a | cut -d/ -f2 | sort | uniq -c | sort -nr
Sebastian Piskorski
sumber
9
Sejauh ini solusi terbaik (dan paling elegan) jika seseorang ingin membuat daftar jumlah file di direktori tingkat atas secara rekursif.
itoctopus
13
Ini memiliki dua masalah: Ini menghitung satu file per direktori lebih dari yang sebenarnya dan memberikan baris tidak berguna yang berisi ukuran direktori saat ini sebagai "1 ukuran ". Keduanya bisa diperbaiki dengan du -a | sed '/.*\.\/.*\/.*/!d' | cut -d/ -f2 | sort | uniq -c. Tambahkan | sort -nruntuk mengurutkan menurut hitungan, bukan nama direktori.
makanan penutup pada
3
Saya ingin menunjukkan bahwa ini juga berfungsi di OSX. (Hanya salin-tempel saran Linux ke shell OSX biasanya tidak berfungsi.)
Pistos
2
itu mengambil ukuran yang tidak dibutuhkan oleh du -a. Cara yang lebih baik adalah menggunakan perintah find. tapi ide utamanya persis sama :)
Znik
5
Temukan . -tipe f | potong -d / -f2 | urutkan | uniq -c | sort -nr # memperbaiki masalah yang disebutkan oleh makanan penutup
jcomeau_ictx
28
find . -type f | cut -d/ -f2 | sort | uniq -c
  • find. -type f untuk menemukan semua item dari file tipe
  • cut -d/ -f2 untuk memotong folder khusus mereka
  • sort untuk mengurutkan daftar nama folder
  • uniq -c untuk mengembalikan berapa kali setiap nama folder telah dihitung
DCZ
sumber
8
Ini jauh lebih baik daripada jawaban yang diterima, karena Anda mendapatkan ringkasan direktori tingkat atas!
Jason Floyd
3
Ini harus menjadi jawaban yang diterima. Sederhana dan mudah dipahami.
xssChauhan
1
Jawaban terbaik yang harus diterima adalah yang ini.
loretoparisi
1
Sederhana, elegan, dan cocok untuk kebutuhan saya.
RichR
Sempurna. Dan dapat diperpanjang untuk menghitung subdirektori dengan mengganti penentu bidang dengan daftar penentu bidang. Misalnya ,:find . -type f | cut -d/ -f2,3 | sort | uniq -c
algal
15

Anda dapat mengatur untuk menemukan semua file, menghapus nama file, meninggalkan baris yang hanya berisi nama direktori untuk setiap file, dan kemudian menghitung berapa kali setiap direktori muncul:

find . -type f |
sed 's%/[^/]*$%%' |
sort |
uniq -c

Satu-satunya gotcha dalam hal ini adalah jika Anda memiliki nama file atau nama direktori yang berisi karakter baris baru, yang sangat tidak mungkin. Jika Anda benar-benar harus khawatir tentang baris baru dalam nama file atau nama direktori, saya sarankan Anda menemukannya, dan memperbaikinya sehingga tidak mengandung baris baru (dan diam-diam membujuk pihak yang bersalah atas kesalahan cara mereka).


Jika Anda tertarik dengan jumlah file di setiap sub-direktori dari direktori saat ini, menghitung file apa pun di sub-direktori apa pun bersama dengan file di sub-direktori langsung, maka saya akan menyesuaikan sedperintah untuk hanya mencetak direktori tingkat atas:

find . -type f |
sed -e 's%^\(\./[^/]*/\).*$%\1%' -e 's%^\.\/[^/]*$%./%' |
sort |
uniq -c

Pola pertama menangkap awal nama, titik, garis miring, nama hingga garis miring berikutnya dan garis miring, dan menggantikan garis hanya dengan bagian pertama, jadi:

./dir1/dir2/file1

diganti dengan

./dir1/

Replace kedua menangkap file secara langsung di direktori saat ini; mereka tidak memiliki garis miring di bagian akhir, dan diganti dengan ./. Sortir dan hitungan kemudian bekerja hanya pada jumlah nama.

Jonathan Leffler
sumber
1
Ini tidak menghasilkan nama direktori yang tidak berisi file apa pun. Tidak yakin apakah ini diperlukan.
Austin Phillips
Benar, tidak. Ini tidak terlalu sepele untuk memperbaikinya untuk melakukannya, karena nama direktori yang kosong bahkan tidak dijamin untuk muncul dalam keluaran find. Beberapa mungkin: jika ada file dir1/dir2/dir3/file1, tetapi dir1/dir2hanya berisi sub-direktori (tidak ada file biasa), Anda dapat menyimpulkan keberadaannya. Tetapi jika dir1/dir4tidak memiliki file, namanya tidak muncul.
Jonathan Leffler
Jawaban yang sangat berguna jika Anda hanya ingin melihat subdirektori dari direktori saat ini.
xixixao
Hanya mampir untuk mengucapkan terima kasih. 3 tahun setelah ini diposting, saya ingin menghitung folder tingkat 2 per folder. Posting Anda menyelamatkan saya dari potensi berjam-jam mengutak-atik sed, temukan dan siapa yang tahu apa lagi
Corvin
13

Inilah salah satu cara untuk melakukannya, tetapi mungkin bukan yang paling efisien.

find -type d -print0 | xargs -0 -n1 bash -c 'echo -n "$1:"; ls -1 "$1" | wc -l' --

Memberikan keluaran seperti ini, dengan nama direktori diikuti dengan jumlah entri dalam direktori tersebut. Perhatikan bahwa jumlah keluaran juga akan menyertakan entri direktori yang mungkin bukan yang Anda inginkan.

./c/fa/l:0
./a:4
./a/c:0
./a/a:1
./a/a/b:0
Austin Phillips
sumber
Tampaknya sangat mahal untuk menjalankan 3 perintah ( bash, ls, wc) untuk setiap direktori ditemukan oleh find.
Jonathan Leffler
@JonathanLeffler Setuju, oleh karena itu baris pertama jawaban saya. Solusi Anda lebih baik.
Austin Phillips
keren ini yang saya cari, bolehkah saya bertanya apa '-' di bagian akhir?
sekali
1
@ sekali The - termasuk dalam perintah bash yang akan dikeluarkan oleh xargs. Dari man bash, A -- signals the end of options and disables further option processing. Dalam kasus ini, ini akan mencegah file yang salah bernama yang ditemukan sebagai bagian dari pencarian menjadi bagian dari pemrosesan argumen untuk bash.
Austin Phillips
8

Solusi setiap orang memiliki satu kelemahan atau lainnya.

find -type d -readable -exec sh -c 'printf "%s " "$1"; ls -1UA "$1" | wc -l' sh {} ';'

Penjelasan:

  • -type d: kami tertarik pada direktori.
  • -readable: Kami hanya menginginkannya jika memungkinkan untuk mencantumkan file di dalamnya. Perhatikan bahwa findmasih akan mengeluarkan kesalahan saat mencoba mencari lebih banyak direktori di dalamnya, tetapi ini mencegah pemanggilannya -exec.
  • -exec sh -c BLAH sh {} ';': untuk setiap direktori, jalankan fragmen skrip ini, dengan $0set ke shdan $1setel ke nama file.
  • printf "%s " "$1": cetak nama direktori secara portabel dan minimal, diikuti hanya dengan spasi, bukan baris baru.
  • ls -1UA: daftar file, satu per baris, dalam urutan direktori (agar pipa tidak terhenti), tidak termasuk hanya direktori khusus .dan..
  • wc -l: hitung garis
o11c
sumber
1
Modifikasi untuk menampilkan file diperhitungkan pertama kali di telepon, dan untuk mengurutkan berdasarkan mereka:find -type d -readable -exec sh -c 'ls -1UA "$1" | wc -l | tr -d "\n" ; printf "\t%s\n" "$1" ' sh {} ';' | sort -n
Evgeni Sergeev
itu mengeksekusi shell berkali-kali, kemudian lambat dan sangat menggunakan sumber daya.
Znik
6

Versi jawaban Sebastian yang sedikit dimodifikasi menggunakan findalih-alih du(untuk mengecualikan overhead terkait ukuran file yang duharus dilakukan dan yang tidak pernah digunakan):

 find ./ -mindepth 2 -type f | cut -d/ -f2 | sort | uniq -c | sort -nr

-mindepth 2parameter digunakan untuk mengecualikan file di direktori saat ini. Jika Anda menghapusnya, Anda akan melihat beberapa baris seperti berikut:

  234 dir1
  123 dir2
    1 file1
    1 file2
    1 file3
      ...
    1 fileN

(seperti duvarian berbasis)

Jika Anda juga perlu menghitung file dalam direktori saat ini, gunakan versi yang disempurnakan ini:

{ find ./ -mindepth 2 -type f | cut -d/ -f2 | sort && find ./ -maxdepth 1 -type f | cut -d/ -f1; } | uniq -c | sort -nr

Outputnya akan seperti berikut:

  234 dir1
  123 dir2
   42 .
Yoory N.
sumber
5

Ini juga dapat dilakukan dengan mengulang ls daripada menemukan

for f in */; do echo "$f -> $(ls $f | wc -l)"; done

Penjelasan:

for f in */; - mengulang semua direktori

do echo "$f -> - mencetak setiap nama direktori

$(ls $f | wc -l) - panggil ls untuk direktori ini dan hitung baris

Sixhobbit
sumber
1
Ini tidak bekerja dengan baik jika nama direktori mengandung spasi putih.
Xylol
Cobafor f ./* ; do echo $f $(ls "$f" | wc -l); done
4ndt3s
3

Ini harus mengembalikan nama direktori diikuti dengan jumlah file di direktori.

findfiles() {
    echo "$1" $(find "$1" -maxdepth 1 -type f | wc -l)
}

export -f findfiles

find ./ -type d -exec bash -c 'findfiles "$0"' {} \;

Contoh keluaran:

./ 6
./foo 1
./foo/bar 2
./foo/bar/bazzz 0
./foo/bar/baz 4
./src 4

The export -fdiperlukan karena -execargumen findtidak memungkinkan melaksanakan fungsi pesta kecuali Anda menjalankan pesta eksplisit, dan Anda perlu untuk mengekspor fungsi yang didefinisikan dalam lingkup saat ini ke shell baru secara eksplisit.

Tuxdude
sumber
Ini sepertinya terlalu rumit. Menurut saya, ini juga memberikan jumlah kumulatif untuk hierarki direktori seperti ./dir1/dir2/dir3(menghitung file di dir1dan subdirektorinya bersama-sama, daripada menghitung file secara dir1/dir2/dir3terpisah dari yang ada di dir1/dir2dan keduanya secara terpisah dari yang ada di /dir1).
Jonathan Leffler
Saya mengerti bahwa itulah yang diinginkan penulis. Jika tidak demikian, maka saya setuju bahwa jawabannya tidak relevan dengan pertanyaan tersebut.
Tuxdude
1
@JonathanLeffler - Oke, membaca pertanyaan itu sekali lagi, saya menyadari bahwa Anda benar - telah mengubah jawaban yang sesuai.
Tuxdude
2

Saya menggabungkan jawaban @glenn jackman dan jawaban @ pcarvalho (di daftar komentar, ada yang salah dengan jawaban pcarvalho karena fungsi kontrol gaya ekstra dari karakter ' `` (backtick)).

Skrip saya dapat menerima path sebagai augument dan mengurutkan daftar direktori sebagai ls -l, juga dapat menangani masalah "spasi dalam nama file" .

#!/bin/bash
OLD_IFS="$IFS"
IFS=$'\n'
for dir in $(find $1 -maxdepth 1 -type d | sort); 
do
    files=("$dir"/*)
    printf "%5d,%s\n" "${#files[@]}" "$dir"
done
FS="$OLD_IFS"

Jawaban pertama saya di stackoverflow, dan saya harap ini dapat membantu seseorang ^ _ ^

vacing
sumber
1

Temukan . -ketik f -printf '% h \ n' | urutkan | uniq -c

memberi contoh:

  5 .
  4 ./aln
  5 ./aln/iq
  4 ./bs
  4 ./ft
  6 ./hot
Pusing
sumber
0

Saya mencoba dengan beberapa yang lain di sini tetapi berakhir dengan subfolder yang termasuk dalam jumlah file ketika saya hanya menginginkan file. Ini mencetak ./folder/path<tab>nnndengan jumlah file, tidak termasuk subfolder, untuk setiap subfolder di folder saat ini.

for d in `find . -type d -print` 
do 
  echo -e "$d\t$(find $d -maxdepth 1 -type f -print | wc -l)"
done
sthames42
sumber
0

Cara mudah untuk menemukan file dari jenis tertentu secara rekursif. Dalam kasus ini, file .jpg untuk semua folder di direktori saat ini:

find . -name *.jpg -print | wc -l

RexBarker
sumber
0

Perintah keajaiban super cepat, yang secara rekursif melintasi file untuk menghitung jumlah gambar dalam direktori dan mengatur keluaran dengan ekstensi gambar:

find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'

Penghargaan: https://unix.stackexchange.com/a/386135/354980

tsveti_iko
sumber
0

Ini bisa menjadi cara lain untuk menelusuri struktur direktori dan memberikan hasil yang mendalam.

find . -type d  | awk '{print "echo -n \""$0"  \";ls -l "$0" | grep -v total | wc -l" }' | sh 
Joseph Earnest
sumber
0

Saya mengedit skrip untuk mengecualikan semua node_modulesdirektori di dalam direktori yang dianalisis.

Ini dapat digunakan untuk memeriksa apakah jumlah proyek file melebihi jumlah maksimum yang dapat ditangani pengamat file.

find . -type d ! -path "*node_modules*" -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done

Untuk memeriksa file maksimum yang dapat ditonton oleh sistem Anda:

cat /proc/sys/fs/inotify/max_user_watches

node_modules folder harus ditambahkan ke jalur yang dikecualikan IDE / editor Anda dalam sistem yang lambat, dan jumlah file lainnya idealnya tidak boleh melebihi jumlah maksimum (yang dapat diubah sekalipun).

Funder
sumber
-1

Ini akan memberikan hitungan keseluruhan.

for file in */; do echo "$file -> $(ls $file | wc -l)"; done | cut -d ' ' -f 3| py --ji -l 'numpy.sum(l)'
Naga Venkatesh Gavini
sumber
Tidak, tidak akan. Ini hanya akan mempertimbangkan satu tingkat subdirektori.
Kusalananda