2009-03-10 7 views
17

Je souhaite obtenir la liste des dossiers au niveau actuel (sans inclure leurs sous-dossiers) et simplement imprimer le nom du dossier et le nombre de fichiers dans le dossier (de préférence filtrer sur * .jpg si possible). Est-ce possible dans le shell bash standard? ls -l impressions sur tout, mais le nombre de fichiers :)Commande UNIX pour lister les dossiers avec le nombre de fichiers

+2

à la personne qui a voté à proximité: bash est une langue réelle . – Bernard

Répondre

21

Je suis venu avec celui-ci:

find -maxdepth 1 -type d | while read dir; do 
    count=$(find "$dir" -maxdepth 1 -iname \*.jpg | wc -l) 
    echo "$dir ; $count" 
done 

déposer la deuxième -maxdepth 1 si la recherche dans les répertoires des fichiers jpg doit être récursive considérer les sous-répertoires . Notez que cela ne considère que le nom des fichiers. Vous pouvez renommer un fichier, en cachant que c'est une image jpg. Vous pouvez utiliser la commande file pour faire une estimation sur le contenu, au lieu (maintenant, les recherches aussi récursive):

find -mindepth 1 -maxdepth 1 -type d | while read dir; do 
    count=$(find "$dir" -type f | xargs file -b --mime-type | 
      grep 'image/jpeg' | wc -l) 
    echo "$dir ; $count" 
done 

Cependant, ce qui est beaucoup plus lent, car il doit lire une partie des fichiers et éventuellement interpréter ce ils contiennent (s'il a de la chance, il trouve un identifiant magique au début du fichier). Le -mindepth 1 l'empêche d'imprimer . (le répertoire en cours) en tant qu'un autre répertoire qu'il recherche.

1
#!/bin/bash 
for dir in `find . -type d | grep -v "\.$"`; do 
echo $dir 
ls $dir/*.jpg | wc -l 
done; 
8

le mien est plus rapide à taper de la ligne de commande. :)

Les autres suggestions offrent-elles un réel avantage par rapport aux suivantes?

find -name '*.jpg' | wc -l    # recursive 


find -maxdepth 1 -name '*.jpg' | wc -l # current directory only 
+0

exemple: l'enseignant veut lister les photos jpg de ses élèves. donc il met la commande dans/home et veut lister tous les jpg dans ces sous-répertoires pour valider qu'ils ne contiennent pas quelques *** choses :) exemple de mon précédent enseignant unix. il savait de quoi il parlait: p ppls a essayé de cacher leur pr0n dans les fichiers bin: D –

+0

Cela imprime seulement le nombre total de fichiers, pas le nombre par dossier. Je l'ai fait maintenant de toute façon, suite au commentaire ci-dessus. – DisgruntledGoat

+0

@DisgruntledGoat, j'ai mal interprété votre question. Désolé pour ça. Je comprends maintenant. – m42

1

Vous pouvez le faire sans commandes externes:

for d in */; do 
    set -- "$d"*.jpg 
    printf "%s: %d\n" "${d%/}" "$#" 
done 

Ou vous pouvez utiliser awk (nawk ou /usr/xpg4/bin/awk sur Solaris):

printf "%s\n" */*jpg | 
    awk -F\/ 'END { 
    for (d in _) 
     print d ":",_[d] 
     } 
    { _[$1]++ }' 
9

J'ai trouvé cette question afte J'avais déjà trouvé mon propre script similaire. Il semble s'adapter à vos conditions et est très flexible, donc j'ai pensé que je l'ajouterais comme une réponse.

Avantages:

  • peuvent être regroupées pour toute profondeur (0 pour ., 1 pour les sous-répertoires de premier niveau, etc.)
  • impressions assez sortie
  • pas de boucle, et une seule commande find, donc il est un peu plus rapide sur les grands répertoires
  • peut encore être réglé pour ajouter des filtres personnalisés (maxdepth pour le rendre non récurrent, le motif de nom de fichier)

Code Raw:

find -P . -type f | rev | cut -d/ -f2- | rev | \ 
     cut -d/ -f1-2 | cut -d/ -f2- | sort | uniq -c 

Emballé en fonction et a expliqué:

fc() { 
    # Usage: fc [depth >= 0, default 1] 
    # 1. List all files, not following symlinks. 
    #  (Add filters like -maxdepth 1 or -iname='*.jpg' here.) 
    # 2. Cut off filenames in bulk. Reverse and chop to the 
    #  first/(remove filename). Reverse back. 
    # 3. Cut everything after the specified depth, so that each line 
    #  contains only the relevant directory path 
    # 4. Cut off the preceeding '.' unless that's all there is. 
    # 5. Sort and group to unique lines with count. 

    find -P . -type f \ 
     | rev | cut -d/ -f2- | rev \ 
     | cut -d/ -f1-$((${1:-1}+1)) \ 
     | cut -d/ -f2- \ 
     | sort | uniq -c 
} 

produit une sortie comme ceci:

$ fc 0 
1668 . 

$ fC# depth of 1 is default 
    6 . 
    3 .ssh 
    11 Desktop 
    44 Downloads 
1054 Music 
550 Pictures 

Bien sûr, avec le premier numéro, il peut être canalisé à sort:

$ fc | sort 
    3 .ssh 
    6 . 
    11 Desktop 
    44 Downloads 
550 Pictures 
1054 Music 
+0

Sous Solaris, il n'y a pas de 'rev' disponible. Vous pouvez utiliser 'perl' à la place comme solution universelle: ' find -P. -type f | perl -lpe '$ _ = reverse' | couper -d/-f2- | perl -lpe '$ _ = reverse' | coupé -d/-f1-2 | couper -d/-f2- | trier | uniq -c' –

Questions connexes