web-dev-qa-db-fra.com

Comment compter le nombre de fichiers dans chaque répertoire?

Je suis capable de lister tous les répertoires par

find ./ -type d

J'ai tenté de répertorier le contenu de chaque répertoire et de compter le nombre de fichiers dans chaque répertoire à l'aide de la commande suivante

find ./ -type d | xargs ls -l | wc -l

Mais ceci résume le nombre total de lignes retournées par

find ./ -type d | xargs ls -l

Est-il possible de compter le nombre de fichiers dans chaque répertoire?

69
user784637

En supposant que vous avez GNU find, laissez-le trouver les répertoires et laissez bash faire le reste:

find . -type d -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done
78
glenn jackman

Ceci imprime le nombre de fichiers par répertoire pour le niveau de répertoire actuel:

du -a | cut -d/ -f2 | sort | uniq -c | sort -nr
105
Sebastian Piskorski

Vous pouvez organiser la recherche de tous les fichiers, supprimer les noms de fichiers, en laissant une ligne contenant uniquement le nom du répertoire pour chaque fichier, puis compter le nombre de fois où chaque répertoire apparaît:

find . -type f |
sed 's%/[^/]*$%%' |
sort |
uniq -c

La seule chose à laquelle il faut en venir est si vous avez des noms de fichier ou de répertoire contenant un caractère de nouvelle ligne, ce qui est assez improbable. Si vous devez vraiment vous soucier des nouvelles lignes dans les noms de fichier ou de répertoire, je vous suggère de les trouver et de les corriger afin qu'elles ne contiennent pas de nouvelles lignes (et persuadez le coupable de son erreur).


Si vous êtes intéressé par le nombre de fichiers dans chaque sous-répertoire du répertoire actuel, en comptant tous les fichiers dans tous les sous-répertoires ainsi que les fichiers dans le sous-répertoire immédiat, alors j'adapterais la commande sed pour imprimer uniquement le répertoire de niveau supérieur:

find . -type f |
sed -e 's%^\(\./[^/]*/\).*$%\1%' -e 's%^\.\/[^/]*$%./%' |
sort |
uniq -c

Le premier motif capture le début du nom, le point, la barre oblique, le nom jusqu'à la barre oblique suivante et la barre oblique, et remplace la ligne par la première partie uniquement, ainsi:

./dir1/dir2/file1

est remplacé par

./dir1/

Le second remplacement capture les fichiers directement dans le répertoire en cours; ils n'ont pas de barre oblique à la fin, et ceux-ci sont remplacés par ./. Le tri et le compte ne fonctionnent que sur le nombre de noms. 

12
Jonathan Leffler

Voici une façon de le faire, mais probablement pas la plus efficace.

find -type d -print0 | xargs -0 -n1 bash -c 'echo -n "$1:"; ls -1 "$1" | wc -l' --

Donne une sortie comme celle-ci, avec le nom du répertoire suivi du nombre d'entrées de ce répertoire. Notez que le nombre de sorties comprendra également des entrées de répertoire qui peuvent ne pas être ce que vous voulez.

./c/fa/l:0
./a:4
./a/c:0
./a/a:1
./a/a/b:0
11
Austin Phillips

La solution de tout le monde a un inconvénient ou un autre.

find -type d -readable -exec sh -c 'printf "%s " "$1"; ls -1UA "$1" | wc -l' sh {} ';'

Explication:

  • -type d: les répertoires nous intéressent.
  • -readable: Nous ne les voulons que s'il est possible de lister leurs fichiers. Notez que find émettra quand même une erreur quand il essaiera de rechercher plus de répertoires dans ces répertoires, mais cela empêchera d'appeler -exec pour eux.
  • -exec sh -c BLAH sh {} ';': pour chaque répertoire, exécutez ce fragment de script, avec $0 défini sur sh et $1 défini sur le nom du fichier.
  • printf "%s " "$1": affiche de manière portable et minimale le nom du répertoire, suivi uniquement d'un espace, pas d'une nouvelle ligne.
  • ls -1UA: liste les fichiers, un par ligne, dans l’ordre des répertoires (pour ne pas bloquer le tuyau), à l’exception de seulement des répertoires spéciaux . et ..
  • wc -l: compter les lignes
7
o11c

Version légèrement modifiée de Sebastian answer utilisant find au lieu de du (pour exclure la surcharge liée à la taille du fichier que du doit effectuer et qui n'est jamais utilisée):

 find ./ -mindepth 2 -type f | cut -d/ -f2 | sort | uniq -c | sort -nr

Le paramètre -mindepth 2 est utilisé pour exclure les fichiers du répertoire en cours. Si vous le supprimez, vous verrez un tas de lignes comme celles-ci:

  234 dir1
  123 dir2
    1 file1
    1 file2
    1 file3
      ...
    1 fileN

(un peu comme la variante basée sur du-)

Si vous devez également compter les fichiers dans le répertoire en cours, utilisez cette version améliorée:

{ find ./ -mindepth 2 -type f | cut -d/ -f2 | sort && find ./ -maxdepth 1 -type f | cut -d/ -f1; } | uniq -c | sort -nr

Le résultat sera le suivant:

  234 dir1
  123 dir2
   42 .
2
Yoory N.

trouver . -type f -printf '% h\n' | trier | uniq -c

donne par exemple:

  5 .
  4 ./aln
  5 ./aln/iq
  4 ./bs
  4 ./ft
  6 ./hot
1
Giddy

Cela devrait renvoyer le nom du répertoire suivi du nombre de fichiers qu'il contient.

findfiles() {
    echo "$1" $(find "$1" -maxdepth 1 -type f | wc -l)
}

export -f findfiles

find ./ -type d -exec bash -c 'findfiles "$0"' {} \;

Exemple de sortie:

./ 6
./foo 1
./foo/bar 2
./foo/bar/bazzz 0
./foo/bar/baz 4
./src 4

export -f est requis car l'argument -exec de find n'autorise pas l'exécution d'une fonction bash, sauf si vous appelez explicitement bash et exportez explicitement la fonction définie dans l'étendue actuelle vers le nouveau shell.

1
Tuxdude

Je vis cela ici, pour le rappel futur

ls |parallel 'echo {} && ls {}|wc -l'
1
emanuele

Cela donnera le nombre total.

for file in */; do echo "$file -> $(ls $file | wc -l)"; done | cut -d ' ' -f 3| py --ji -l 'numpy.sum(l)'
0

Une commande miracle super rapide, qui parcourt de manière récursive des fichiers pour compter le nombre d'images d'un répertoire et organiser la sortie par extension d'image:

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

Crédits: https://unix.stackexchange.com/a/386135/35498

0
tsveti_iko

J'ai combiné les réponses de @glenn jackman et de @ pcarvalho (dans la liste des commentaires, il y a un problème avec la réponse de pcarvalho car la fonction de contrôle de style supplémentaire du caractère '`' (backtick)).

Mon script peut accepter chemin comme un augument et trier la liste de répertoires comme étant ls -l. Il peut également gérer le problème de "l'espace dans le nom du fichier".

#!/bin/bash
OLD_IFS="$IFS"
IFS=$'\n'
for dir in $(find $1 -maxdepth 1 -type d | sort); 
do
    files=("$dir"/*)
    printf "%5d,%s\n" "${#files[@]}" "$dir"
done
FS="$OLD_IFS"

Ma première réponse dans stackoverflow, et j'espère que cela peut vous aider ^ _ ^

0
vacing

Un moyen facile de rechercher récursivement des fichiers d'un type donné. Dans ce cas, les fichiers .jpg de tous les dossiers du répertoire en cours:

find . -name *.jpg -print | wc -l

0
Rex Barker

J'ai essayé avec certains des autres ici, mais j'ai fini avec des sous-dossiers inclus dans le nombre de fichiers alors que je ne voulais que les fichiers. Ceci imprime ./folder/path<tab>nnn avec le nombre de fichiers, sous-dossiers non compris, pour chaque sous-dossier du dossier actuel.

for d in `find . -type d -print` 
do 
  echo -e "$d\t$(find $d -maxdepth 1 -type f -print | wc -l)"
done
0
sthames42
find . -type f | cut -d/ -f2 | sort | uniq -c
  • find. -type f pour trouver tous les éléments du fichier type
  • cut -d/ -f2 pour couper leur dossier spécifique
  • sort pour trier la liste des noms de répertoire
  • uniq -c pour renvoyer le nombre de fois que chaque nom de dossier a été compté
0
DCZ