Soru Dosyaları sayan bir bash komutu var mı?


Bir desenle eşleşen dosya sayısını sayan bir bash komutu var mı?

Örneğin, bu kalıpla eşleşen bir dizindeki tüm dosyaların sayısını almak istiyorum: log*


76
2017-07-03 08:35


Menşei




Cevaplar:


Bu basit tek katlı, sadece bash değil, herhangi bir kabukta çalışmalıdır:

ls -1q log* | wc -l

ls -1q, boşluklar veya yeni satırlar gibi özel karakterler içermesine rağmen dosya başına bir satır verecektir.

Çıkış, satır sayısını sayan wc -l'ye bağlanır.


102
2017-07-03 08:41



Kullanmazdım -lçünkü bu gerektirir stat(2) her dosyada ve sayma amacıyla hiçbir şey eklemez. - camh
Kullanmazdım lsÇünkü bir çocuk süreci yaratır. log* kabuk tarafından genişletilir, değil ls, bu yüzden basit echo yapardım. - cdarke
mywiki.wooledge.org/ParsingLs - ormaaj
Aslında "ls -l", çıktı borulandığında dosya başına bir tane basmıyor. touch abc$'\n'def; ls abc*def | wc -l yazdırmazsanız 2 basar, gösterecektir abc?def. ls -1f aynı problemi var. - mogsie
@WalterTross Bu doğrudur (verimlilik, orijinal sorunun bir gerekliliği değildi). Ayrıca çıktı-terminal olmasa bile -q'nin yeni satırlarla dosyalara dikkat ettiğini buldum. Ve bu bayraklar test ettiğim tüm platformlar ve kabuklar tarafından destekleniyor. Cevabın güncellenmesi, size ve camh girişe teşekkürler! - Daniel


Bunu güvenli bir şekilde yapabilirsiniz (yani, boşluk içeren dosyalar tarafından yüklenmeyecek veya \n bash ile)

$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}
$ shopt -u nullglob

Etkinleştirmeniz gerekiyor nullglob böylece edebi almazsın *.log içinde $logfiles  dizi hiçbir dosya eşleşmiyorsa.


33
2017-07-03 08:43





Bunu dene:

echo *.log | wc -w


30
2017-07-03 08:41



echo *.log | wc -w bazı dosyalar adlarında boşluk varsa yanlış sonuç verir - lanzz
@lanzz: Doğru; bunu düşünmemişti! - Will Vousden
Boşluklarla dosyalamam - hudi
Bile sen boşluk içeren dosyalar yoksa, betiğinizin başka bir kullanıcısı kötü amaçlı olarak adlandırılmış bir dosyayla karşılaşabilir ve bu da komut dosyalarının başarısız olmasına neden olabilir. Ayrıca, StackOverflow'ta bununla karşılaşan diğer kişilerin de yeni satırlara sahip dosyaları olabilir ve tuzakları bilmesi gerekir. - mogsie


Burada bir sürü cevap var, ama bazıları hesaba katmıyor

  • boşluk, satırsonu veya kontrol karakterleri içeren dosya adları
  • tire ile başlayan dosya isimleri (bir dosya düşünün) -l)
  • bir nokta ile başlayan gizli dosyalar (eğer glob ise *.log yerine log*
  • glob ile eşleşen dizinler (ör. logs eşleşiyor log*)
  • boş dizinler (yani sonuç 0'dır)
  • son derece büyük dizinler (hepsini listelemek hafızayı tüketebilir)

İşte hepsini ele alan bir çözüm:

ls 2>/dev/null -Ubad1 -- log* | wc -l

Açıklama:

  • -U nedenleri ls girdileri sıralamak değil, yani tüm dizin listelerini belleğe yüklemeye gerek yok
  • -b baskılar C-stili olmayan karakterler için kaçar, önemli olarak yeni satırların yazdırılmasına neden olur. \n.
  • -a Tüm dosyaları, hatta gizli dosyaları basar (glob olduğunda kesinlikle gerekli değildir) log* gizli dosya içermez)
  • -d listelemeye çalışılmadan dizinleri yazdırır içindekiler dizinin ne olduğunu ls normalde yapardı
  • -1 bir sütunda olduğundan emin olur (bu, bir boruya yazarken otomatik olarak bunu yapar, bu yüzden kesinlikle gerekli değildir)
  • 2>/dev/null stderr'i yeniden yönlendirir, böylece 0 günlük dosyası varsa, hata mesajını dikkate almayın. (Bunu not et shopt -s nullglob sebep olur ls bunun yerine tüm çalışma dizinini listelemek için.
  • wc -l dizin listesini oluşturulduğu şekilde tüketir, böylece çıktı ls Zaman içinde herhangi bir noktada asla hafızada değildir.
  • -- Dosya isimleri, komut kullanılarak -- argümanlar olarak anlaşılmamak için ls (bu durumda log* kaldırıldı)

Deniz kabuğu irade genişletmek log* Çok sayıda dosya varsa, belleği tüketebilen dosyaların tam listesi için, grep ile çalıştırılması daha iyi olacaktır:

ls -Uba1 | grep ^log | wc -l

Sonuncusu, çok fazla bellek kullanmadan çok büyük dosya dizinlerini (bir alt kabuk kullanmasa da) kullanmaktadır. -d artık gerekli değil, çünkü sadece geçerli dizinin içeriğini listeliyor.


29
2017-11-24 11:01



Harika cevap ve son derece doğru. - raratiru


Bu sorunun kabul edilen cevabı yanlıştır, ancak düşük bir geri dönüşüme sahip olduğum için yorum ekleyemiyorum.

Bu soruya doğru cevap Mat tarafından verilir:

shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}

Kabul edilen yanıtla ilgili problem, wc -l'nin yeni satır karakterlerinin sayısını sayması ve '' 'olarak terminale yazdırılsa bile bunları saymasıdır. 'ls -l' çıkışında. Bu, bir dosya adının yeni satır karakteri içerdiğinde kabul edilen yanıtın FAILS olduğu anlamına gelir. Önerilen komutu test ettim:

ls -l log* | wc -l

ve adı bir satırsonu karakteri içerecek şekilde eşleşen yalnızca 1 dosya olsa bile 2 değerini hatalı olarak bildirir. Örneğin:

touch log$'\n'def
ls log* -l | wc -l

5
2017-10-30 06:11





Çok fazla dosya varsa ve zarif kullanmak istemiyorsanız shopt -s nullglob ve bash dizisi çözümü, dosya adını (yeni satırlar içerebilecek) yazdıramıyorsanız, bulmayı da kullanabilirsiniz.

find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l

Bu, log * ile eşleşen tüm dosyaları bulacaktır. .* - "İsim değil. *" İfadesi reddidir, ancak "ls" için varsayılan ayarın nokta-dosyaları göstermemek olduğunu, ancak bulmak için varsayılanların bunları içermek olduğunu belirtmek önemlidir.

Bu doğru bir cevaptır ve üzerine atabileceğiniz her türlü dosya adını işleyebilir, çünkü dosya adı hiçbir zaman komutlar arasında geçmez.

Ama shopt nullglob cevap en iyi cevaptır!


4
2017-08-22 19:16



Muhtemelen cevaplamak yerine orijinal cevabınızı güncellemeniz gerekir. - qodeninja
Kullanmayı düşünüyorum find vs kullanarak ls Sorunu çözmenin iki farklı yolu vardır. find bir makinede her zaman mevcut değildir, ancak ls genellikle - mogsie


İşte bunun için tek çarşafım.

 file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)

2
2017-11-04 19:48