Bir dizindeki dosyaları uzantıya göre say


16

Test amacıyla, bir dizin içinde kaç görüntü dosyasının olduğunu saymak isterim, her görüntü dosyası türünü dosya uzantısına (jpg = "yes") ayırarak daha sonra bir eylem yürütecek başka bir komut dosyası için yararlı olacaktır her dosya uzantısında). Yalnızca JPEG dosyaları için aşağıdakine benzer bir şey kullanabilir miyim?

jpg=""
count=`ls -1 *.jpg 2>/dev/null | wc -l`
if [ $count != 0 ]
then
echo jpg files found: $count ; jpg="yes"
fi

Jpg, png, bmp, raw ve diğer dosya uzantıları göz önüne alındığında, whilebunu yapmak için bir döngü kullanmalı mıyım?

Yanıtlar:


14

Farklı bir yaklaşım öneririm. ls

#!/bin/bash

shopt -s nullglob

for ext in jpg png gif; do 
  files=( *."$ext" )
  printf 'number of %s files: %d\n' "$ext" "${#files[@]}"

  # now we can loop over all the files having the current extension
  for f in "${files[@]}"; do
    # anything else you like with these files
    :
  done 

done

filesHer bir uzantının dosyalarında gerçekleştirmek istediğiniz diğer komutlarla dizi üzerinde döngü yapabilirsiniz .


Daha portatif olarak - veya açık bir şekilde diziler sağlamayan kabuklar için - kabuğun konumsal parametre dizisini yeniden kullanabilirsiniz.

set -- *."$ext"

ve daha sonra değiştirmek ${#files[@]}ve ${files[@]}ile $#ve"$@"


25

Benim yaklaşımım:

  1. Dizindeki tüm dosyaları listele
  2. Uzantılarını çıkarın
  3. Sonucu sırala
  4. Her uzantının oluşumunu sayın

Şöyle bir şekilde (son awkçağrı yalnızca biçimlendirme içindir):

ls -q -U | awk -F . '{print $NF}' | sort | uniq -c | awk '{print $2,$1}'

(GNU varsayarak lsburada için -Ubir optimizasyon olarak tasnif atlamak için seçenek. O yapabilirsiniz güvenle desteklenmiyorsa eğer işlevselliğini etkilemeden kaldırılabilir).


mhmh ... daha sonra bunun için bir eylem yapmak için bulunan her uzantıyı filtrelemeliyim?
watchmansky

Sonunda ne yapmak istediğinize bağlı. Daha fazla bilgi verebilir misiniz?
groxxda

Amacım: girdi kullanıcı verilerinden boyutu değiştiren her uzantı dosyasını (yalnızca görüntü dosyası) işleyen bir komut dosyası. Yani, kaç jpg dosyası var, bir sonraki png vb.
watchmansky

steeldrivers çözeltisi daha uygun olabilir.
groxxda

2
Ben de vardı JPGve jpgbenim çözüm yazmaktı yinelemeli böylece dosyalar ve istediğifind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian

11

Bu, özyinelemeli dosyaları tarar ve eşleşen uzantıları sayar:

$ find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'
   6 tiff
   7 bmp
  26 jpeg
  38 gif
  51 jpg
  54 png

6
find -type f | sed -e 's/.*\.//' | sort | uniq -c

3
İle bir başlangıç ​​dizini unutmayın find. Ayrıca, çözümünüz hakkında kısa bir açıklama yaparsanız (biraz farklı bir durum için değiştirmek istediklerinde) bu cevapların gelecekteki okuyucularına yardımcı olabilir.
Jeff Schaller

Bu çözüm boşluk içeren yol adları ile ne kadar iyi başa çıkıyor? Yeni satırların?
dhag

1
findvarsayılan olarak geçerli dizini kullanır, bunu nasıl kullanırım. Tanrı'nın dosya adlarının içinde boşluk olmasını amaçladığını düşünmüyorum, ancak bu durum için iyi çalışıyor. Eğer yeni satırlarınız varsa, elde ettiğiniz her şeyi hak ediyorsunuz. Bir açıklama düşündüm ama cevabın çok uzun sürmesine karar verdim, bence önemli olan basitlik. Vakaların% 99'u zamanın% 1'inde. Bu muhtemelen Sürüm 7 ile uyumludur.
Neik

3

Belki daha kısa olabilir

exts=( *.jpg *.png *.gif ); printf "There are ${#exts[@]}" extensions;

3

İlgili her lsşeyin özel karakterlerle (boşluk ve diğer semboller) beklenmedik sonuçlar üretmesi muhtemeldir. Herhangi bir bashizm (diziler gibi) taşınabilir değildir. İçeren her şey while readgenellikle yavaştır.

Öte yandan, findÇOK esnek (filtreleme seçenekleri bir sürü), özel karakterleri için güvenli başarısız en az iki sözdizimi vardır ... ve büyük dizinde iyi ölçeklendirir.

Bu örnekte, -inamehem büyük hem de küçük harfli uzantı adıyla eşleştim. Ayrıca -maxdepth 1sorunuzun "geçerli dizinde" saygı gösterilmesini de kısıtladım . Dosya adlarının CR / LF içerebileceği satır sayısını saymak yerine -print0, her dosya adının sonuna bir NULL bayt yazdıracaktır ... bu yüzden | tr -d -c "\000" | wc -ldosyaları doğru şekilde sayar (NULL bayt!).

extensions="jpg png gif"
for ext in $extensions; do
  c=$(find . -maxdepth 1 -iname "*.$ext" -print0 | tr -d -c "\000" | wc -c)
  if [ $c -gt 0 ]; then
    echo "Found $c  *.$ext files"

    find . -maxdepth 1 -iname "*.$ext" -print0 | xargs -0 -r -n1 DOSOMETHINGHERE
    # or #  find . -maxdepth 1 -iname "*.$ext" -exec "ls" "-l" "{}" ";"
  fi
done

PS veya hatta -print0 | tr -d -c "\000" | wc -cdeğiştirilebilir .-printf "\000" | wc -c-printf '\n' | wc -l


0

ls bu basit IMO bir şey için kullanabilirsiniz

ls -l /opt/ssl/certs/*.pem | wc -l

veya

count=$(ls -l /some/folder/*.jpg | wc -l)

veya

ls *.{mp3,exe,mp4} 2>/dev/null | wc -l

-2

Eğer uzatma eminseniz, sizinle gidebilir findgibi

find *.jpeg | wc -l

biri yaratılana touch $'foo\nbar.jpegve bir kez yerine iki kez sayılır. Ya da daha kötüsü, birisi yaparmkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Jeff Schaller
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.