Tüm alt dizinleri kontrol etmem ve kaç tane dosya (daha fazla özyineleme yapmadan) içerdiklerini bildirmem gerekiyor:
directoryName1 numberOfFiles
directoryName2 numberOfFiles
Tüm alt dizinleri kontrol etmem ve kaç tane dosya (daha fazla özyineleme yapmadan) içerdiklerini bildirmem gerekiyor:
directoryName1 numberOfFiles
directoryName2 numberOfFiles
Yanıtlar:
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 $f
dosya adı içeriyordu -test
, find
sadece 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 find
bakmak ./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 find
emir basit -exec echo \;
ve değil -exec echo {} \;
. Dosyaları okumak için sadece yeni bir satır yazdırmak istiyorum.
-mindepth 1
-printf '\n'
yerine de kullanabilirsiniz -exec echo
.
-printf
varsa, ancak örneğin FreeBSD'de çalışmasını istiyorsanız, yapabilirsiniz.
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 find
a, belirtilen iki alt dizinleri erişir -maxdepth
daha özyinelemeye önler 1 ve sadece (dosyaları raporları -type f
) yeni satır ile birbirlerinden ayrılmıştır. Sonuç daha sonra wc
bu satırların sayısını saymak için birleştirilir.
find . -maxdepth 1 -type d
çıktı ile nasıl birleştirebilirim ?
find $dirs ...
veya (b) yalnızca bir üst seviye dizinde ise, bu find */ ...
-exec echo
Bul komutunuza ekleyin - bu şekilde dosya adını, sadece bir yeni satırı eklemez.
“Ö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
-f
Testin 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 -f
ile -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
).
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 %q
Bir 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'
.
find
Komut basitçe her dosya için tek bir karakterin baskı ve ardından yerine sayma hatlarının olanlar hesaplayarak çalışır.
İşte kullanarak, sonuç almak için bir "kaba kuvvet" -ish yolu find
, echo
, ls
, wc
, xargs
ve awk
.
find . -maxdepth 1 -type d -exec sh -c "echo '{}'; ls -1 '{}' | wc -l" \; | xargs -n 2 | awk '{print $1" "$2}'
for i in *; do echo $i; ls $i | wc -l; done
for i in `ls -1`; do echo $i : `ls -1 $i|wc -l`; done
find
Bash 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ç..
)