Yanıtlar:
Bu basit tek astar, sadece bash'da değil, herhangi bir kabukta çalışmalıdır:
ls -1q log* | wc -l
ls -1q, boşluk veya satırsonu gibi özel karakterler içeriyor olsalar bile, dosya başına bir satır verir.
Çıktı, hat sayısını sayan wc -l'ye bağlanır.
lsBir çocuk süreci yarattığı için kullanmam . log*kabuk tarafından genişletildi, değil ls, bu yüzden basit bir echoyapardı.
logsSöz konusu dizinde çağrılan bir dizin varsa , o günlük dizininin içeriği de sayılır. Bu muhtemelen kasıtlı değildir.
Bunu güvenli bir şekilde yapabilirsiniz (yani boşluklu veya \nadlarındaki dosyalar tarafından hatalandırılmaz ) bash ile:
$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}
Sen etkinleştirmeniz gerekir nullglobdeğişmeziyle alamadım böylece *.logde $logfiles dizinin hiçbir dosya eşleşirse. (Bkz "geri alma" Bir 'dizi-x'? Nasıl güvenle sıfırlamak için nasıl örnekler için.)
shopt -u nullglobeğer nullglobayarlanmamışsa final atlanmalı, o zaman başladınız.
*.logSadece yerine *koymak dizinleri sayar. Numaralandırmak istediğiniz dosyalar geleneksel adlandırma kuralına sahipse name.extension, kullanın *.*.
Burada bir sürü cevap var, ama bazıları dikkate almıyor
-l)*.logyerinelog*logs, eşleşen bir dizin log*)İşte hepsini halledecek bir çözüm:
ls 2>/dev/null -Ubad1 -- log* | wc -l
Açıklama:
-Ulsgirişlerin sıralanmamasına neden olur , yani tüm dizin listesinin belleğe yüklenmesi gerekmez-bC olmayan stil karakterleri için C-tarzı çıkış karakterleri yazdırır, bu da özellikle satırsonu olarak yazdırılır \n.-a tüm dosyaları, hatta gizli dosyaları yazdırır (glob olduğunda kesinlikle gerekli değildir) log* hiçbir gizli dosya gerektirmediğinde )-dListeye girişiminde bulunulmadan dizinlere dışarı baskılar içeriğini nedir dizine ait lsnormalde yapacağını-1 bir sütunda olduğundan emin olur (ls bunu bir boruya yazarken otomatik olarak yapar, bu yüzden kesinlikle gerekli değildir)2>/dev/null0 günlük dosyası varsa, hata iletisini yok saymak için stderr'i yeniden yönlendirir. ( Bunun yerine tüm çalışma dizinini listelemenize shopt -s nullglobneden olacağını unutmayın ls.)wc -ldizin listesini oluşturulurken kullanır, bu nedenle çıktısı lshiçbir zaman hafızada kalmaz.--Dosya adları, --argüman olarak anlaşılmayacak şekilde ls( log*kaldırıldığında) komuttan ayrılırKabuk edecek genişletmek log*o dosyaların bir sürü eğer grep aracılığıyla çalışan öyleyse, hafızayı tüketmesine dosyaların tam listesi daha iyi olduğunu:
ls -Uba1 | grep ^log | wc -l
Bu sonuncusu, çok fazla bellek kullanmadan (büyük bir alt kabuk kullanmasına rağmen) çok büyük dosya dizinlerini işler. -dSadece geçerli dizinin içeriğini listeleyen çünkü, artık gerekli değildir.
Yinelemeli arama için:
find . -type f -name '*.log' -printf x | wc -c
wc -cçıkışında karakter sayısını sayar findiken, -printf xsöyler findtek yazdırmak xHer sonuç için.
Özyinelemesiz arama için şunları yapın:
find . -maxdepth 1 -type f -name '*.log' -printf x | wc -c
-name '*.log', tüm dosyaları sayar, bu da benim kullanım durumum için gerekli olan şeydir. Ayrıca -maxdepth bayrağı son derece kullanışlıdır, teşekkürler!
find; sadece sözlü dosya adından başka bir şey yazdırın.
Bu soru için kabul edilen cevap yanlış, ama düşük temsilcisi var, bu yüzden ona yorum ekleyemiyorum.
Bu soruya doğru cevap Mat tarafından verilir:
shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}
Kabul edilen cevapla ilgili sorun, wc -l'nin satırsonu karakter sayısını sayması ve terminale '?' Olarak yazdırsa bile bunları saymasıdır. 'ls -l' çıktısında. Bu, bir dosya adı yeni satır karakteri içerdiğinde kabul edilen yanıtın başarısız olduğu anlamına gelir. Önerilen komutu test ettim:
ls -l log* | wc -l
ve ismi yeni satır karakteri içerecek şekilde kalıpla eşleşen 1 dosya olsa bile hatalı olarak 2 değerini bildirir. Örneğin:
touch log$'\n'def
ls log* -l | wc -l
Çok fazla dosyanız varsa ve zarif shopt -s nullglobve bash dizi çözümünü kullanmak istemiyorsanız, dosya adını (yeni satırlar içerebilir) yazdırmazsanız find ve benzerlerini kullanabilirsiniz.
find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l
Bu, log * ile eşleşen ve ile başlamayan tüm dosyaları bulur .* . Bulmak onları dahil etmektir.
Bu doğru bir yanıttır ve ona atabileceğiniz her türlü dosya adını işler, çünkü dosya adı hiçbir zaman komutlar arasında aktarılmaz.
Ama shopt nullglobcevap en iyi cevap!
findvs kullanarak lssorunu çözmenin iki farklı yolu var. findbir makinede her zaman mevcut değildir, ancak lsgenellikle,
findmuhtemelen bir tane domuz yağı kutusu da bu seçeneklerin hepsine sahip değil ls.
-maxdepth 1
findbunu varsayılan olarak yapar. Bu, gizli bir alt klasör olduğunu fark etmez ve lsbazı durumlarda varsayılan olarak gizli dosyaları rapor etmeyen avantajlı olabilir .
İşte bunun için tek astarım.
file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)
set -- bizim için hazırlanıyor dışında hiçbir şey yapmıyor $#ki kabuk programına geçirildi komut satırı argüman sayısı mağazalarında
(yorum yapmak için yeterli itibar)
Bu HATA :
ls -1q some_pattern | wc -l
Eğer shopt -s nullglobayarlanacak olur, bu sayısını yazdırır TÜM normal dosyalar, desenli sadece olanları (CentOS-8 ve Cygwin üzerinde test). Diğer anlamsız hataların ne olduğunu kim bilebilir ls?
Bu DOĞRU ve çok daha hızlı:
shopt -s nullglob; files=(some_pattern); echo ${#files[@]};
Beklenen işi yapar.
0.006CentOS ve 0.083Cygwin'de (dikkatli kullanılması durumunda).
İkincisi 0.000CentOS'ta ve 0.003Cygwin'de.
Bir kabuk işlevi kullanarak böyle bir komutu kolayca tanımlayabilirsiniz. Bu yöntem herhangi bir harici program gerektirmez ve alt süreç oluşturmaz. Tehlikeli lsayrıştırma girişiminde bulunmaz ve “özel” karakterleri (beyaz boşluklar, yeni satırlar, ters eğik çizgiler vb.) İyi işler. Yalnızca kabuk tarafından sağlanan dosya adı genişletme mekanizmasına dayanır. En az sh, bash ve zsh ile uyumludur.
Aşağıdaki satır, çağrıldığı countargüman sayısını yazdıran bir işlev tanımlar .
count() { echo $#; }
İstediğiniz desenle arayın:
count log*
Globbing paterni eşleşmediğinde sonucun doğru olması için, genişletme gerçekleştiğinde kabuk seçeneği nullglob(veya failglob- zsh'de varsayılan davranış olan) ayarlanmalıdır. Bu şekilde ayarlanabilir:
shopt -s nullglob # for sh / bash
setopt nullglob # for zsh
Neyi saymak istediğinize bağlı olarak, kabuk seçeneğiyle de ilgilenebilirsiniz dotglob.
Ne yazık ki, en azından bash ile, bu seçenekleri yerel olarak ayarlamak kolay değildir. Bunları küresel olarak ayarlamak istemiyorsanız, en basit çözüm işlevi bu daha kıvrımlı bir şekilde kullanmaktır:
( shopt -s nullglob ; shopt -u failglob ; count log* )
Hafif sözdizimini kurtarmak istiyorsanız count log*veya gerçekten bir alt kabuk ortaya çıkmasını önlemek istiyorsanız, aşağıdaki satırlarda bir şeyleri hackleyebilirsiniz:
# sh / bash:
# the alias is expanded before the globbing pattern, so we
# can set required options before the globbing gets expanded,
# and restore them afterwards.
count() {
eval "$_count_saved_shopts"
unset _count_saved_shopts
echo $#
}
alias count='
_count_saved_shopts="$(shopt -p nullglob failglob)"
shopt -s nullglob
shopt -u failglob
count'
Bir bonus olarak, bu fonksiyon daha genel bir kullanıma sahiptir. Örneğin:
count a* b* # count files which match either a* or b*
count $(jobs -ps) # count stopped jobs (sh / bash)
İşlevi PATH'den çağrılan bir komut dosyasına (veya eşdeğer bir C programına) dönüştürerek, findve gibi programlarla da oluşturulabilir xargs:
find "$FIND_OPTIONS" -exec count {} \+ # count results of a search
Bu cevaba birçok düşünce verdim, özellikle ayrıştırmayan şeyler göz önüne alındığında . İlk başta denedim
<UYARI! ÇALIŞMADI>
du --inodes --files0-from=<(find . -maxdepth 1 -type f -print0) | awk '{sum+=int($1)}END{print sum}'
</ UYARI! ÇALIŞMADI>
sadece bir dosya adı olsaydı işe yaradı.
touch $'w\nlf.aa'
ama böyle bir dosya adı yaptıysam başarısız oldum
touch $'firstline\n3 and some other\n1\n2\texciting\n86stuff.jpg'
Sonunda aşağıya koyduğum şeyi buldum. Not (herhangi bir alt dizin dahil değil) dizindeki tüm dosyaların sayısını almaya çalışıyordum. @Mat ve @Dan_Yard'ın cevaplarıyla birlikte, @mogsie tarafından belirlenen gereksinimlerin en azından çoğuna sahip olduğumu düşünüyorum (bellek hakkında emin değilim.) @Mogsie'nin cevabının doğru olduğunu düşünüyorum, ama lsçok özel bir durum olmadıkça ayrıştırmadan uzak durmaya çalışıyorum .
awk -F"\0" '{print NF-1}' < <(find . -maxdepth 1 -type f -print0) | awk '{sum+=$1}END{print sum}'
Daha okunaklı:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -print0) | \
awk '{sum+=$1}END{print sum}'
Bu, dosyalar için özel olarak bir bulma işlemi yapar, çıktıyı boş karakterle sınırlar (boşluklar ve satır beslemeleriyle ilgili sorunları önlemek için), ardından boş karakter sayısını sayar. Sonunda boş bir karakter olacağından, dosya sayısı boş karakter sayısından bir az olacaktır.
OP'nin sorusunu cevaplamak için dikkate alınması gereken iki durum var
1) Özyinelemesiz arama:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
2) Özyinelemeli arama. -nameParametrenin içindekilerin biraz farklı davranışlar (gizli dosyalar vb.) İçin değiştirilmesi gerekebileceğini unutmayın .
awk -F"\0" '{print NF-1}' < \
<(find . -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
Eğer birisi bu cevapların bu cevapta bahsettiğim cevaplarla nasıl karşılaştırıldığını yorumlamak isterse, lütfen yapınız.
Not, bu yanıtı alırken bu düşünce sürecine girdim .
İşte her zaman yaptığım:
ls günlüğü * | awk 'END {yazdır NR}'
awk 'END{print NR}'ile eşdeğer olmalıdır wc -l.
ls -1 log* | wc -l
Bu, satır başına bir dosya listelemek ve daha sonra satırları saymak için parametre değiştirme ile sözcük sayımı komutuna bağlamak anlamına gelir.
-l, çünkü bustat(2)her dosyada gerektirir ve sayma amacıyla hiçbir şey ekler.