Nombre de fichiers dans chaque sous-répertoire

21

Je voudrais qu'une commande BASH liste juste le nombre de fichiers dans chaque sous-répertoire d'un répertoire.

Par exemple , dans le répertoire /tmpil y a dir1, dir2... Je voudrais voir:

`dir1` : x files 
`dir2` : x files ...
jldupont
la source

Réponses:

32

En supposant que vous souhaitiez uniquement un nombre récursif de fichiers, pas de répertoires et d'autres types, quelque chose comme ceci devrait fonctionner:

find . -maxdepth 1 -mindepth 1 -type d | while read dir; do
  printf "%-25.25s : " "$dir"
  find "$dir" -type f | wc -l
done
Thor
la source
De plus, j'obtiens "find: warning: vous avez spécifié l'option -maxdepth après un argument non-option -type, mais les options ne sont pas positionnelles (-maxdepth affecte les tests spécifiés avant lui ainsi que ceux spécifiés après). Veuillez spécifier les options avant les autres arguments. "
jldupont
2
Les deux réponses données jusqu'à présent donneront des résultats incorrects dans le cas peu probable où il existe des fichiers dont les noms contiennent des caractères de nouvelle ligne. Vous pouvez gérer cela avec un find... -print0 | xargs -0....
Scott
@jldupont: déplacez les arguments de profondeur avant le "type", j'ai édité la réponse.
Thor
Oui, et permettez-moi d'ajouter les informations selon lesquelles cette excellente solution ne prendra aucune variable externe et fonctionnera donc avec bash alias!!
erreur de syntaxe
rapide, et la tuyauterie sort -rn -k 2,2 -t$':'vous obtenez la liste DESC
Andre Figueiredo
14

Cette tâche m'a tellement fasciné que j'ai voulu trouver moi-même une solution. Cela ne prend même pas une boucle de temps et PEUT être plus rapide en vitesse d'exécution. Inutile de dire que les efforts de Thor m'ont beaucoup aidé à comprendre les choses en détail.

Alors, voici le mien:

find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "{} : $(find "{}" -type f | wc -l)" file\(s\)' \;

Il semble modeste pour une raison, car il est beaucoup plus puissant qu'il n'y paraît. :-)

Cependant, si vous avez l'intention de l'inclure dans votre .bash_aliasesfichier, il doit ressembler à ceci:

alias somealias='find . -maxdepth 1 -mindepth 1 -type d -exec sh -c '\''echo "{} : $(find "{}" -type f | wc -l)" file\(s\)'\'' \;'

Notez la gestion très délicate des guillemets simples imbriqués . Et non, il n'est pas possible d'utiliser des guillemets doubles pour l' sh -cargument.

erreur de syntaxe
la source
Il est plus lent car il appelle / bin / sh pour chaque répertoire. Vous pouvez vérifier cela avec strace -fc script. Votre version effectue environ 70% d'appels système supplémentaires. +1 pour le code plus court :-)
Thor
1
inspiré par cela; triés par nombre de fichiers:find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "$(find "{}" -type f | wc -l)" {}' \; | sort -nr
mnagel
7
find . -type f | cut -d"/" -f2 | uniq -c

Répertorie les dossiers et les fichiers du dossier actuel avec un nombre de fichiers trouvés en dessous. IMO rapide et utile. (les fichiers montrent avec le compte 1).

non merci
la source
1
Que diriez-vous d'une petite explication de la façon dont cela fonctionne? :)
C0deDaedalus
1
super merci! Vous voudrez peut-être ajouter | sort -rnpour trier les sous-répertoires par nombre de fichiers.
Dennis Golomazov
1

L'utilisation de find est certainement la voie à suivre si vous voulez compter de manière récursive, mais si vous voulez juste un décompte des fichiers directement sous un certain répertoire:

ls dir1 | wc -l

jrajav
la source
Je ne veux pas faire ça pour chacun des 1000 répertoires que j'ai là ...
jldupont
Ensuite, utilisez xargs. ls -d */ | xargs -n1 ls | wc -l(Utilisez la réponse que vous avez acceptée si cela fonctionne déjà! C'est juste et maintenant vous savez.)
jrajav
votre proposition n'a pas montré de résultats en plusieurs secondes alors que la réponse que j'ai acceptée l'a fait.
jldupont
@jrajav, cette approche échoue absolument pour les répertoires contenant des espaces. C'est pourquoi findc'est si important. (encore moins -print0et xargs -0, déjà souligné par Scott dans l'autre réponse)
erreur de syntaxe
1
find . -mindepth 1 -type d -print0 | xargs -0 -I{} sh -c 'printf "%4d : %s\n" "$(find {} -type f | wc -l)" "{}"'

J'ai souvent besoin de compter le nombre de fichiers dans mes sous-répertoires et d'utiliser cette commande. Je préfère que le décompte apparaisse en premier.

Teddy Katayama
la source
0

Ce que j'utilise ... Cela fait un tableau de tous les sous-répertoires dans celui que vous donnez comme paramètre. Imprimez le sous-répertoire et le nombre de ce même sous-répertoire jusqu'à ce que tous les sous-répertoires soient traités.

#!/bin/bash    
directories=($(/bin/ls -l $1 | /bin/grep "^d" | /usr/bin/awk -F" " '{print $9}'))

for item in ${directories[*]}
    do
        if [ -d "$1$item" ]; then
            echo "$1$item"
            /bin/ls $1$item | /usr/bin/wc -l
        fi
    done
derberlinersmurf
la source
0

Vous pouvez utiliser ce code python. Démarrez l'interpréteur en exécutant python3et collez ceci:

folder_path = '.'
import os, glob
for folder in sorted(glob.glob('{}/*'.format(folder_path))):
    print('{:}: {:>8,}'.format(os.path.split(folder)[-1], len(glob.glob('{}/*'.format(folder)))))

Ou une version récursive pour les nombres imbriqués:

import os, glob
def nested_count(folder_path, level=0):
    for folder in sorted(glob.glob('{}/'.format(os.path.join(folder_path, '*')))):
        print('{:}{:}: {:,}'.format('    '*level, os.path.split(os.path.split(folder)[-2])[-1], len(glob.glob(os.path.join(folder, '*')))))
        nested_count(folder, level+1)
nested_count('.')

Exemple de sortie:

>>> figures: 5
>>> misc: 1
>>> notebooks: 5
>>>     archive: 65
>>>     html: 12
>>>     py: 12
>>>     src: 14
>>> reports: 1
>>>     content: 6
>>> src: 1
>>>     html_download: 1
AlexG
la source