Apa cara terbaik untuk menghitung jumlah file dalam direktori?

11

Jika parsing output lsberbahaya karena dapat merusak beberapa karakter yang funky (spasi \n,, ...), apa cara terbaik untuk mengetahui jumlah file dalam direktori?

Saya biasanya mengandalkan finduntuk menghindari parsing ini, tetapi juga, find mydir | wc -lakan rusak karena alasan yang sama.

Saya sedang mengerjakan Solaris saat ini, tetapi saya sedang mencari jawaban yang portabel seperti di berbagai kesatuan dan kulit yang berbeda.

rahmu
sumber
3
Saya tidak yakin ini duplikat, apakah saya melewatkan sesuatu?
rahmu
1
Ini mungkin duplikat, tetapi bukan dari pertanyaan yang ditunjukkan. findakan memberi Anda jumlah file secara rekursif (gunakan -maxdepth 1jika Anda tidak menginginkannya. Anda find mydir -maxdepth 1 -type f -printf \\n | wc -lharus menangani karakter khusus dalam nama file, karena mereka tidak pernah dicetak sejak awal.
Anthon

Jawaban:

16

Bagaimana dengan trik ini?

find . -maxdepth 1 -exec echo \; | wc -l

Sebagai portabel seperti finddan wc.

rozcietrzewiacz
sumber
5
Ini tidak berfungsi (ini menampilkan n+1file di sistem Debian saya). Itu juga tidak memfilter untuk file biasa.
Chris Down
4
Saya baru saja memberi contoh umum. Itu memang berhasil, tetapi cara kerjanya tergantung pada bagaimana Anda menyesuaikan findperintah dengan kebutuhan spesifik Anda. Ya, ini termasuk semua direktori, termasuk .(yang mungkin mengapa Anda melihat hasilnya sebagai n+1).
rozcietrzewiacz
Saya suka trik ini, sangat pintar; tapi saya terkejut tidak ada cara mudah dan sederhana untuk melakukan itu!
rahmu
3
@ ChrisDown OP tidak menentukan penyaringan untuk file biasa, menanyakan jumlah file dalam direktori. Untuk menyingkirkan masalah n +1, gunakan find . -maxdepth 1 ! -name . -exec echo \; | wc -l; beberapa versi yang lebih lama findtidak memiliki -not.
Arcege
3
Catatan yang -maxdepthtidak standar (ekstensi GNU sekarang juga didukung oleh beberapa implementasi lainnya).
Stéphane Chazelas
11

Dengan bash, tanpa utilitas eksternal, atau loop:

shopt -s dotglob
files=(*)
echo ${#files[@]}

Di ksh, ganti shopt -s dotglobdengan FIGNORE=.?(.). Di zsh, ganti dengan setopt glob_dots, atau hapus shoptpanggilan dan gunakan files=(*(D)). (Atau cukup hapus baris jika Anda tidak ingin menyertakan file dot.) Mudah-mudahan, jika Anda tidak peduli dengan file dot:

set -- *
echo $#

Jika Anda ingin menyertakan file dot:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c
enzotib
sumber
2
Contoh pertama mencetak 1untuk direktori kosong ketika nullglobtidak diaktifkan. Di zsh, a=(*(DN));echo ${#a}dengan kualifikasi N( nullglob) tidak menghasilkan kesalahan untuk direktori kosong.
nisetama
8
find . ! -name . -prune -print | grep -c /

Seharusnya cukup portabel untuk sistem pasca-80-an.

Itu menghitung semua entri direktori kecuali .dan ..di direktori saat ini.

Untuk menghitung file dalam subdirektori juga:

find .//. ! -name . | grep -c //

(Yang itu harus portabel bahkan untuk Unix V6 (1975), karena tidak perlu -prune)

Stéphane Chazelas
sumber
Salah satu jawaban portabel yang langka di halaman ini, jika bukan satu-satunya.
xhienne
Saya memutakhirkan jawaban ini kemarin karena ternyata juga berfungsi dengan baik untuk direktori selain direktori saat ini ( find dirname ! -name dirname -prune -print). Sejak itu saya bertanya-tanya apakah ada alasan khusus untuk digunakan grep -c /sebagai pengganti wc -l(yang mungkin lebih umum digunakan untuk menghitung).
Anthony Geoghegan
1
find dirname ! -name dirnametidak berfungsi jika ada direktori lain di dalamnya yang dinamai dirname. Lebih baik digunakan find dirname/. ! -name .. wc -lmenghitung jumlah baris, nama file dapat dibuat dari beberapa baris karena karakter baris baru sama validnya dengan nama file.
Stéphane Chazelas
6

Mencoba:

ls -b1A | wc -l

The -bakan memiliki karakter non-printable, -Aakan menampilkan semua file kecuali .dan ..dan satu per baris (default pada pipa, tapi bagus untuk menjadi eksplisit).

Selama kami menyertakan bahasa skrip tingkat tinggi, inilah satu-baris di Python:

python -c 'import os; print len(os.listdir(os.sep))'

Atau dengan 'temukan' lengkap:

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'
Arcege
sumber
1

Yoc dapat menggunakan konstruksi seperti itu:

I=0; for i in * ; do ((I++)); done ; echo $I

Tapi saya khawatir, Anda dapat melakukan kesalahan seperti Argument list too long.jika Anda memiliki terlalu banyak file dalam direktori. Namun saya mengujinya di direktori dengan 10 miliar file, dan itu bekerja dengan baik.

buru-buru
sumber
3
Ini tidak akan berfungsi untuk file tersembunyi, kecuali jika shell dikonfigurasikan untuk mengembangkannya *.
Lekensteyn
gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley
4
@Rush: perintah ini seharusnya tidak pernah menaikkan "daftar arg terlalu panjang". Itu hanya terjadi dengan perintah eksternal (jadi tidak pernah dengan for.
enzotib
1

Sudahkah Anda mempertimbangkan perl, yang seharusnya relatif portabel?

Sesuatu seperti:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";
cjc
sumber
0

Coba ini => Menggunakan ls dengan opsi -i (untuk nomor simpul) & -F (menambahkan nama direktori dengan opsi '/').

ls -ilF | egrep -v '/' | wc -l
Saumil
sumber
0

Dengan perlone-liner (diformat ulang agar mudah dibaca):

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

atau

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

Anda dapat menggunakan perlfungsi yang memodifikasi array seperti grepatau mapdengan versi kedua. Lihat perldoc -f readdircontoh menggunakan grep.

cas
sumber
0

Versi paling sederhana yang saya gunakan sepanjang waktu dan tidak pernah bermasalah adalah: ls -b1 | wc -l

Peter
sumber
Anda mungkin mengalami masalah jika nama file berisi \nkarakter funky atau lainnya (yeah, beberapa tertentu mengizinkan ini).
rahmu
1
Saya mencoba ini secara eksplisit sebelum memposting jawaban saya dan tidak punya masalah dengan itu. Saya menggunakan pengelola file nautilus untuk mengubah nama file menjadi berisi \ n untuk mencoba ini.
Peter
Anda benar itu tidak berfungsi seperti itu. Saya tidak tahu apa yang saya lakukan ketika saya menguji ini dulu. Mencoba lagi dan memperbarui jawaban saya.
Peter
Tidak, perintahnya OK, tetapi sudah ada solusi serupa dan file tersembunyi tidak dihitung.
xhienne
0

Selain findjawaban berbasis yang diajukan oleh Stéphane , berikut adalah jawaban yang sesuai dengan POSIX berdasarkan ls:

ls -qf | tail -n +3 | wc -l
xienne
sumber