Compter les fichiers dans un répertoire par extension

15

À des fins de test, je voudrais compter le nombre de fichiers images dans un répertoire, en séparant chaque type de fichier image par extension de fichier (jpg = "yes". Ceci car plus tard, il sera utile pour un autre script qui exécutera une action sur chaque extension de fichier). Puis-je utiliser quelque chose comme le suivant pour les fichiers JPEG uniquement?

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

Compte tenu des extensions de fichier jpg, png, bmp, raw et autres, dois-je utiliser un whilecycle pour ce faire?

watchmansky
la source

Réponses:

14

Je suggérerais une approche différente, en évitant les éventuels problèmes de 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

Vous pouvez parcourir le filestableau avec toutes les autres commandes que vous souhaitez exécuter sur les fichiers de chaque extension particulière.


Plus facilement - ou pour les shells qui ne fournissent pas explicitement des tableaux - vous pouvez réutiliser le tableau de paramètres positionnels du shell, c'est-à-dire

set -- *."$ext"

puis remplacer ${#files[@]}et ${files[@]}avec $#et"$@"

tournevis
la source
23

Mon approche serait:

  1. Liste tous les fichiers du répertoire
  2. Extraire leur extension
  3. Trier le résultat
  4. Compter les occurrences de chaque extension

Un peu comme ça (le dernier awkappel est purement pour le formatage):

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

(en supposant GNU lsici pour l' -Uoption d'ignorer le tri comme une optimisation. Il peut être supprimé en toute sécurité sans affecter la fonctionnalité s'il n'est pas pris en charge).

groxxda
la source
mhmh ... plus tard, devrais-je filtrer chaque extension trouvée pour faire une action pour elle?
watchmansky
Cela dépend de ce que vous voulez faire à la fin. Pouvez-vous donner plus d'informations?
groxxda
Mon objectif: un script qui traite chaque fichier d'extension (uniquement le fichier image) en changeant la taille à partir des données utilisateur d'entrée. Donc, je commence par le nombre de fichiers jpg, le prochain png, etc.
watchmansky
La solution Steeldrivers pourrait alors être plus appropriée.
groxxda du
2
J'avais les deux JPGet les jpgfichiers, et je le voulais récursivement donc ma solution était d'écrirefind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian
11

Cela traverse récursivement les fichiers et compte les extensions qui correspondent:

$ 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
Trousse
la source
6
find -type f | sed -e 's/.*\.//' | sort | uniq -c
Neik
la source
3
N'oubliez pas un répertoire de départ avec find. En outre, cela peut aider les futurs lecteurs de ces réponses si vous donnez une brève explication de votre solution (au cas où ils souhaiteraient la modifier pour un cas légèrement différent).
Jeff Schaller
Dans quelle mesure cette solution gère-t-elle les noms de chemin contenant des espaces? De nouvelles lignes?
dhag
1
findpar défaut dans le répertoire courant, c'est ainsi que j'utilise ceci. Je ne pense pas que Dieu voulait que les noms de fichiers contiennent des espaces, mais cela fonctionne bien pour ce cas. Si vous avez des nouvelles lignes, vous méritez tout ce que vous obtenez. J'ai pensé à une explication mais j'ai décidé que cela rendrait la réponse trop longue, je pense que la simplicité est ce qui compte. 99% des cas dans 1% du temps. Ceci est probablement compatible avec la version 7.
Neik
3

Peut-être que ça peut raccourcir

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

Tout ce qui implique lsest susceptible de produire des résultats inattendus avec des caractères spéciaux (espace et autres symboles). Tout bashisme (comme les tableaux) n'est pas portable. Tout ce qui implique while readest généralement lent.

D'un autre côté, il findest TRÈS flexible (beaucoup d'options à filtrer), il a [au moins] deux syntaxes qui sont sûres pour les caractères spéciaux ... et il évolue bien sur un grand répertoire.

Pour cet exemple, j'ai utilisé -inamepour faire correspondre le nom de l'extension en majuscule et en minuscule. J'ai également restreint le -maxdepth 1respect de votre question "dans le répertoire courant". Plutôt que de compter le nombre de lignes, où les noms de fichiers pourraient inclure CR / LF, -print0affichera un octet NULL à la fin de chaque nom de fichier ... tout | tr -d -c "\000" | wc -lcomme le comptage précis des fichiers (octets NULL!).

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 -print0 | tr -d -c "\000" | wc -cpeut être remplacé par -printf "\000" | wc -cou même -printf '\n' | wc -l.

Franklin Piat
la source
0

peut simplement utiliser ls pour quelque chose de ce simple IMO

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

ou

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

ou

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

Si vous êtes sûr de l'extension, vous pouvez aller avec findcomme

find *.jpeg | wc -l
Nithish JV
la source
jusqu'à ce que quelqu'un crée touch $'foo\nbar.jpeget qu'il soit compté deux fois au lieu d'une fois. Ou pire, quelqu'un le faitmkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Jeff Schaller