Neden benden daha fazla dosya sayıyor?


25

Görünüşe göre sayamam. Sanırım içinde üç dosya var./media

$ tree /media
/media
├── foo
├── onex
└── zanna
3 directories, 0 files

Ancak, ls -l12 bulur.

$ ls -l /media
total 12
drwxr-xr-x  2 root root 4096 Jul 31 20:57 foo
drwxrwxr-x  2 root root 4096 Jun 26 06:36 onex
drwxr-x---+ 2 root root 4096 Aug  7 21:17 zanna

Ve eğer yaparsam, ls -lasadece .ve ..yukarıdakilere ek olarak alıyorum , ancak sayımtotal 20

Açıklama nedir?

Yanıtlar:


33

12Gördüğünüz dosya sayısı değil, disk bloklarının sayısı tükettiler.

Kimden info coreutils 'ls invocation':

 For each directory that is listed, preface the files with a line
 `total BLOCKS', where BLOCKS is the total disk allocation for all
 files in that directory.  The block size currently defaults to 1024
 bytes, but this can be overridden (*note Block size::).  The
 BLOCKS computed counts each hard link separately; this is arguably
 a deficiency.

Toplam gider 12için 20kullandığınızda ls -layerine ls -liki ek dizinleri güveniyoruz çünkü: .ve ... Her (boş) dizin için dört disk bloğu kullanıyorsunuz, bu nedenle toplamınız 3 × 4 ile 5 × 4 arasında değişiyor. (Her durumda , sayfaların gösterdiği gibi, her bir dizin için 4096 baytlık bir disk bloğu kullanıyorsunuz ; infoyardımcı programı disk biçimini denetlemez, ancak 1024aksi belirtilmedikçe bir blok boyutu varsayar .)

Dosya sayısını basitçe almak istiyorsanız, bunun gibi bir şey deneyebilirsiniz

ls | wc -l

13
ls | wc -lDosya adında yeni satır olan dosyalar varsa başarısız olur. Bu daha esnek:find . -mindepth 1 -maxdepth 1 -printf . | wc -c
Flimm

20
"dosya adlarında bunlarda yeni bir satır varsa" ... titreme
Petah

8
Gibi man lssöyleyecektir, sen kontrol karakter önleyebilirsiniz -b(kaçar onları) ya da -q(atlar onları). Yani saymak için, ls -1q | wc -lgizli olmayan dosyaları göstermek için güvenli ve doğru. ls -1qA | wc -lgizli dosyaları (ancak saymak .ve ..). Bunun -1yerine kullanıyorum -lçünkü daha hızlı olması gerekiyor.
Oli

18

user4556274 zaten cevap vardır neden . Benim cevabım için ek bilgi sağlamak amacıyla sunulduğunu nasıl düzgün dosyaları saymak.

Unix topluluğunda genel fikir birliği, çıktıların ayrıştırılmasının lsçok kötü bir fikir olduğu , çünkü dosya isimleri kontrol karakterlerini veya gizli karakterleri içerebilir. Örneğin, bir dosya adındaki yeni satır karakteri nedeniyle ls | wc -l, çıktısında 5 satır olduğunu söyleriz ls(aslında sahip olduğu), ancak gerçekte dizinde sadece 4 dosya vardır.

$> touch  FILE$'\n'NAME                                                       
$> ls                                                                         
file1.txt  file2.txt  file3.txt  FILE?NAME
$> ls | wc -l
5

Yöntem 1: yardımcı programı bulma

findGenellikle yaklaşık çalışma dosya adlarını ayrıştırmak için kullanılan komut, yazdırarak Bize yardımcı olabilecek inode numarasını . Bir dizin veya dosya olsun, sadece benzersiz bir inode numarası var. Böylece, kullanarak -printf "%i\n"ve dışarıda .bırakarak -not -name "."dosyaların doğru bir sayımına sahip olabiliriz. ( -maxdepth 1Özyinelemeli alt dizinlere iniş önlemek için kullanımını unutmayın )

$> find  -maxdepth 1 -not -name "." -print                                    
./file2.txt
./file1.txt
./FILE?NAME
./file3.txt
$> find  -maxdepth 1 -not -name "." -printf "%i\n" | wc -l                    
4

Yöntem 2: globstar

Basit, hızlı ve çoğunlukla taşınabilir yöntem:

$ set -- * 
$ echo $#
228

setkomut, kabuğun konum parametrelerini ayarlamak için kullanılır ( $<INTEGER>değişkenler, olduğu gibi echo $1). Bu genellikle /bin/sheksik dizilerin sınırlandırılması etrafında çalışmak için kullanılır . Gille'in Unix ve Linux'taki cevabında ekstra kontroller yapan bir versiyonunu bulabilirsiniz .

bashKullanabileceğimiz dizileri destekleyen kabuklarda

items=( dir/* )
echo ${#items[@]}

steeldriver tarafından yorumlarda önerildiği gibi .

findKullanılan yönteme benzer bir numara wcve globstar, statsatır başına inode sayılarını saymak için kullanılabilir :

$> LC_ALL=C stat ./* --printf "%i\n" | wc -l                                          
4

Alternatif bir yaklaşım, fordöngüde bir joker karakter kullanmaktır . (- 16 skinTenimde öğelerin doğrulanmış sayıdır Not, bu test bu yaklaşım değil mi, hangi alt dizinleri içine iner olmadığını test etmek için farklı bir dizin kullanır ~/bin)

$> count=0; for item in ~/bin/* ; do count=$(($count+1)) ; echo $count ; done | tail -n 1                                
16

Yöntem 3: diğer diller / tercümanlar

Python ayrıca, os.listdir()fonksiyonumun verdiği listenin uzunluğunu ( özyinelemeli olmayan ve sadece argüman olarak verilen dizindeki öğeleri listeleyecek şekilde) yazdırarak sorunlu dosya adlarıyla da başa çıkabilir .

$> python -c "import os ; print os.listdir('.')"                              
['file2.txt', 'file1.txt', 'FILE\nNAME', 'file3.txt']
$>  python -c "import os ; print(len(os.listdir('.')))"                    
4

Ayrıca bakınız


2
Bash'ta başka bir seçenek de bir dizi kullanmak olabilir items=( dir/* ); echo ${#items[@]}( örn shopt -s dotglob. Gizli dosyaları eklemek için).
steeldriver

1
Inode numaralarının basılması, istenirse hardlinks filtrelemeyi kolaylaştırır find | sort -u | wc -l.
Peter Cordes

@ steeldriver: bash-array yönteminin daha hızlı olma ihtimalinin düşük olduğunu düşünüyorum. Özyinelemeli olmasını istiyorsanız, items=( dir/** )(with shopt -s globstar) kullanmanız gerekir , ancak bash, readdir'den fazladan meta veriler kullanmaz, bu nedenle bir dizin olup olmadığını görmek için her dizin girişini kullanır. Birçok dosya sistemi, dosya türünü dizin girişinde saklar, böylece readdir, inode'lara erişmeden döndürebilir. (örneğin, en son varsayılan olmayan XFS buna sahip ve sanırım ext4'ün daha uzun süre sahip olduğunu düşünüyorum.) Bulursanız, bash bascına göre straceçok daha az statsistem çağrısı görürsünüz.
Peter Cordes,

2
Neden sadece kullanmıyorsun print(len(os.listdir('.')))? Yazmak için daha az sayıda karakter bulunur ve ayrıca altta çizilen özniteliklere erişmekten kaçınır.
edwinksl

1
@ edwinksl düzenlendi, thx
Sergiy Kolodyazhnyy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.