Tüm alt dizinlerdeki dosya sayısı nasıl bildirilir?


24

Tüm alt dizinleri kontrol etmem ve kaç tane dosya (daha fazla özyineleme yapmadan) içerdiklerini bildirmem gerekiyor:

directoryName1 numberOfFiles
directoryName2 numberOfFiles

Neden kullanmak istiyorsunuz findBash yapacak zaman? (shopt -s dotglob; for dir in */; do all=("$dir"/*); echo "$dir: ${#all[@]}"; done): tüm dizinler için, bu dizindeki giriş sayısını (gizli nokta dosyaları dahil .ve hariç ..)
sayın

@ janmoesen Neden bir cevap vermedin? Komut dosyası oluşturma konusunda yeniyim, ancak yönteminizle ilgili herhangi bir sonuç göremiyorum. Bana göre, en iyi yol gibi görünüyor. Yorumunuz kimse tarafından beğenilmedi, ancak hiç kimse de neden bu kadar kötü olabileceği konusunda yorum yapmadı. Alınan cevapların senden çok daha fazla yanıtı var, bu yüzden bir şeyleri kaçırıp kaçırmadığımı merak ediyor.
toxalot

@toxalot: Cevap olarak ekleme zahmetine girmedim, çünkü çok kısa (ve muhtemelen hafifçe küçülen). Yorumu yenileştirmekten çekinmeyin. :-) Ayrıca, "kaç dosya" nın ne anlama geldiğiyle ilgili olarak soru biraz belirsizdir. Benim çözümüm "normal" dosya ve dizinleri sayar ; belki de poster gerçekten "dosyalar değil, dizinler" anlamına geliyordu. Akılda tutulması gereken bir başka şey, bu globbing "gizli" nokta dosyaları dikkate almaz olmasıdır. Yine de, bu ikisinin de etrafında yollar var. Ancak yine: orijinal posterin kesin şartlarından emin değiliz.
janmoesen

Yanıtlar:


30

Bu, güvenli ve taşınabilir bir şekilde yapar. Garip dosya isimleriyle karıştırılmaz.

for f in *; do [ -d ./"$f" ] && find ./"$f" -maxdepth 1 -exec echo \; | wc -l && echo $f; done

Önce dosya sayısını, ardından dizin adını ayrı bir satıra yazacağını unutmayın. OP formatını korumak istiyorsanız, daha fazla formatlamaya ihtiyacınız olacak, örn.

for f in *; do [ -d ./"$f" ] && find ./"$f" -maxdepth 1 -exec echo \;|wc -l|tr '\n' ' ' && echo $f; done|awk '{print $2"\t"$1}'

İlgilendiğiniz belirli bir alt dizin kümeniz varsa, onunla değiştirebilirsiniz *.

Bu neden güvenli? (ve bu nedenle senaryoya layık)

Dosya adları dışında herhangi bir karakter içerebilir /. Özel olarak kabuk veya komutlar tarafından ele alınan birkaç karakter vardır. Bunlar boşlukları, yeni satırları ve kısa çizgileri içerir.

Yapıyı kullanmak, for f in *ne olursa olsun, her bir dosya adını almanın güvenli bir yoludur.

Bir değişkende dosya ismine sahip olduğunuzda, bunun gibi şeylerden kaçınmanız gerekir find $f. Eğer $fdosya adı içeriyordu -test, findsadece o verdi seçeneği hakkında şikayet ediyorum. Bundan kaçınmanın yolu ./, adın önünde kullanmaktır ; bu şekilde aynı anlama gelir, ancak artık bir çizgi ile başlamaz.

Yeni satırlar ve boşluklar da bir problemdir. Eğer $f"merhaba dostum" ise, bir dosya adı olarak bulunursa find ./$f, olur find ./hello, buddy. Sen söylüyorsun findbakmak ./hello,ve buddy. Bunlar yoksa, şikayet edecek ve asla içeriye bakmayacak ./hello, buddy. Bunu önlemek kolaydır - değişkenlerinizin etrafında tırnak kullanın.

Son olarak, dosya adları yeni satırlar içerebilir, bu nedenle dosya listesindeki yeni satırları saymak işe yaramaz; newline ile her dosya adı için fazladan bir sayı alacaksınız. Bunu önlemek için, dosya listesindeki yeni satırları saymayın; bunun yerine, tek bir dosyayı temsil eden yeni satırları (veya başka bir karakteri) sayın. Bu yüzden findemir basit -exec echo \;ve değil -exec echo {} \;. Dosyaları okumak için sadece yeni bir satır yazdırmak istiyorum.


1
Neden dünyada dosya adında yeni satırları kullanan biri var? Cevap için teşekkürler.
ShyBoy

1
Dosya isimleri / ve boş karakterler dışında herhangi bir karakter içerebilir, inanıyorum. dwheeler.com/essays/fixing-unix-linux-filenames.html
Flimm

2
Sayı dizinin kendisini içerecektir. Bunu sayıdan hariç tutmak istiyorsanız,-mindepth 1
toxalot 10.04

Bunun -printf '\n'yerine de kullanabilirsiniz -exec echo.
toxalot

1
@toxalot, destekleyen bir bulmanız -printfvarsa, ancak örneğin FreeBSD'de çalışmasını istiyorsanız, yapabilirsiniz.
Shawn J. Goff

6

Standart bir Linux çözümü aradığınızı varsayarsak, bunu başarmanın nispeten basit bir yolu şudur find:

find dir1/ dir2/ -maxdepth 1 -type f | wc -l

Burada finda, belirtilen iki alt dizinleri erişir -maxdepthdaha özyinelemeye önler 1 ve sadece (dosyaları raporları -type f) yeni satır ile birbirlerinden ayrılmıştır. Sonuç daha sonra wcbu satırların sayısını saymak için birleştirilir.


2 dir'den fazla direktörüm var ... Komutunuzu find . -maxdepth 1 -type dçıktı ile nasıl birleştirebilirim ?
ShyBoy

(A) gerekli dizinleri bir değişkene dahil edebilir find $dirs ...veya (b) yalnızca bir üst seviye dizinde ise, bu find */ ...
dizinden

1
Herhangi bir dosya adında yeni bir karakter varsa, bu hatalı sonuçlar verecektir.
Shawn J. Goff,

@Shawn: teşekkürler. Boşluk içeren dosya adlarım olduğunu düşündüm, ancak yeni satırlar düşünmemiştim: herhangi bir öneriniz var mı?
jasonwryan

-exec echoBul komutunuza ekleyin - bu şekilde dosya adını, sadece bir yeni satırı eklemez.
Shawn J. Goff

5

“Özyineleme olmadan” derken directoryName1, alt dizinleri varsa , alt dizinlerdeki dosyaları saymak istemediğinizi mi kastediyorsunuz ? Öyleyse, belirtilen dizindeki tüm normal dosyaları saymanın bir yolu:

count=0
for d in directoryName1 directoryName2; do
  for f in "$d"/* "$d"/.[!.]* "$d"/..?*; do
    if [ -f "$f" ]; then count=$((count+1)); fi
  done
done

-fTestin iki işlevi yerine getirdiğine dikkat edin : yukarıdaki globlardan biri tarafından eşleştirilen girişin normal bir dosya olup olmadığını test eder ve girişin eşleşip eşleşmediğini test eder (globlardan biri hiçbir şeyle eşleşmezse, desen olduğu gibi kalır). Eğer tiplerine bakmaksızın verilen dizinleri tüm girişleri saymak isterseniz, yerini -file -e.

Ksh, desenleri nokta dosyalarıyla eşleştirmenin ve hiçbir dosyanın bir desenle eşleşmemesi durumunda boş bir liste oluşturmanın bir yolunu sunar. Yani ksh içerisinde normal dosyaları şöyle sayabilirsiniz:

FIGNORE='.?(.)'
count=0
for x in ~(N)directoryName1/* ~(N)directoryName2/*; do
  if [ -f "$x" ]; then ((++count)); fi
done

ya da tüm dosyalar bunun gibi:

FIGNORE='.?(.)'
files=(~(N)directoryName1/* ~(N)directoryName2/*)
count=${#files}

Bash'in bunu daha basit hale getirmek için farklı yolları var. Normal dosyaları saymak için:

shopt -s dotglob nullglob
count=0
for x in directoryName1/* directoryName2/*; do
  if [ -f "$x" ]; then ((++count)); fi
done

Tüm dosyaları saymak için:

shopt -s dotglob nullglob
files=(directoryName1/* directoryName2/*)
count=${#files}

Her zamanki gibi, zsh'de daha da basit. Normal dosyaları saymak için:

files=({directoryName1,directoryName2}/*(DN.))
count=$#files

Tüm dosyaları saymak (DN.)için değiştirin (DN).

Pattern Her kalıbın kendisiyle eşleştiğini unutmayın, aksi takdirde sonuçlar kapalı olabilir (örneğin, bir rakamla başlayan dosyaları sayıyorsanız, sadece for x in [0-9]*; do if [ -f "$x" ]; then …bir dosya olduğundan dolayı yapamazsınız [0-9]foo).


2

Bir sayı betiğine göre , Shawn'ın cevabı ve yeni satırlı dosya adlarının bile tek bir satırda kullanılabilir bir formda yazdırıldığından emin olmak için bir Bash numarası:

for f in *
do
    if [ -d "./$f" ]
    then
        printf %q "$f"
        printf %s ' '
        find "$f" -maxdepth 1 -printf x | wc -c
    fi
done

printf %qBir dizenin alıntılanmış bir versiyonunu, yani (potansiyel olarak) newlines ve diğer özel karakterleri içeren değişmez bir string olarak yorumlanabilecek bir Bash betiğine koyabileceğiniz tek bir dizge basmaktır. Örneğin, bakınız echo -n $'\tfoo\nbar'vs printf %q $'\tfoo\nbar'.

findKomut basitçe her dosya için tek bir karakterin baskı ve ardından yerine sayma hatlarının olanlar hesaplayarak çalışır.


1

İşte kullanarak, sonuç almak için bir "kaba kuvvet" -ish yolu find, echo, ls, wc, xargsve awk.

find . -maxdepth 1 -type d -exec sh -c "echo '{}'; ls -1 '{}' | wc -l" \; | xargs -n 2 | awk '{print $1" "$2}'

Bu iş. Ancak adında boşluk bulunan bir diziniz varsa çıktılar karışık.
ShyBoy

Herhangi bir dosya adında yeni bir karakter varsa, bu hatalı sonuçlar verecektir.
Shawn J. Goff,

-1
for i in *; do echo $i; ls $i | wc -l; done

4
U&L'ye hoş geldiniz. Cevaplar açıklamalarla uzun sürmeli ve sadece kod damlalarından oluşmamalıdır. Lütfen bunu genişletin ve neler olduğunu açıklayın. Ayrıca bu, bunu yapmanın çok yetersiz bir yoludur ve örneğin boşluk içeren dosyaları işlemez.
slm

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.