Comptage récursif de fichiers dans un répertoire Linux


729

Comment puis-je compter récursivement des fichiers dans un répertoire Linux?

J'ai trouvé ça:

find DIR_NAME -type f ¦ wc -l

Mais lorsque je l'exécute, il renvoie l'erreur suivante.

find: les chemins doivent précéder l'expression: ¦


64
Vous confondez la barre cassée ¦(ASCII 166) avec la barre verticale |(ASCII 124) utilisée pour le pipeline UNIX .
Skippy le Grand Gourou

7
@SkippyleGrandGourou N'est-il pas appelé un tuyau?
DaveStephens

27
@DaveStephens Oui, c'est aussi ce qu'on appelle. On l'appelle aussi un coup de Sheffer, verti-bar, vbar, bâton, ligne verticale, barre verticale, barre, obélisque, glide.
emlai

64
@zenith Je l'appelle juste Bob.
Christopher

15
Dans la RFC20, cela s'appelle "ligne verticale". "Pipe" est le nom de l'opérateur shell, plutôt que le nom du symbole. Tout comme *le caractère ASCII «astérisque», mais «fois» dans certains autres contextes.
slim

Réponses:


1328

Cela devrait fonctionner:

find DIR_NAME -type f | wc -l

Explication:

  • -type f pour inclure uniquement les fichiers.
  • |( et non¦ ) redirige findla sortie standard de la wccommande vers l'entrée standard de la commande.
  • wc(abréviation de word count) compte les nouvelles lignes, les mots et les octets sur son entrée ( docs ).
  • -l pour ne compter que les nouvelles lignes.

Remarques:

  • Remplacez DIR_NAMEpar .pour exécuter la commande dans le dossier actuel.
  • Vous pouvez également supprimer le -type fpour inclure les répertoires (et les liens symboliques) dans le décompte.
  • Il est possible que cette commande dépasse le nombre si les noms de fichiers peuvent contenir des caractères de nouvelle ligne.

Explication de la raison pour laquelle votre exemple ne fonctionne pas:

Dans la commande que vous avez montrée, vous n'utilisez pas le "Pipe" ( |) pour connecter en quelque sorte deux commandes, mais la barre cassée ( ¦) que le shell ne reconnaît pas comme une commande ou quelque chose de similaire. C'est pourquoi vous obtenez ce message d'erreur.


27
L' fen -type fsignifie des fichiers et wc -ldes lignes de comptage de mots.
Serge Stroobandt

3
Supprimez le -type fpour inclure les répertoires dans le décompte
phatblat

3
Pas besoin de -printdrapeau
Zoltán

3
S'il existe une possibilité que les noms de fichier contiennent le caractère de nouvelle ligne, vous pouvez utiliser l' -print0indicateur.
gaboroncancio

2
@gaboroncancio Cela ne va pas aider, à moins qu'une implémentation de wcn'ait une option pour lire une liste terminée par null. Voir ma réponse pour une alternative.
Réinstallez Monica Please

100

Pour le répertoire actuel:

find -type f | wc -l

5
Cette solution ne prend pas en compte les noms de fichiers contenant des sauts de ligne.
Kusalananda

2
Pour le répertoire actuel, vous n'avez même pas besoin du.
baptx

1
En fait, sur certaines plates - formes, vous avez besoin de préciserfind .
tripleee

1
@Kusalanandra Votre commentaire s'applique à presque toutes les réponses ici.
tripleee

69

Si vous voulez une ventilation du nombre de fichiers dans chaque répertoire sous votre répertoire actuel:

for i in */ .*/ ; do 
    echo -n $i": " ; 
    (find "$i" -type f | wc -l) ; 
done

Cela peut aller tout sur une seule ligne, bien sûr. Les parenthèses clarifient dont la sortie wc -lest censée regarder ( find $i -type fdans ce cas).


7
Il pourrait rester bloqué sur des répertoires avec des espaces dans leurs noms. Changer la première ligne pour la find . -maxdepth 1 -type d -print0 | while IFS= read -r -d '' i ; docorriger. Voir Comment puis-je lire un fichier (flux de données, variable) ligne par ligne (et / ou champ par champ)?
Arch Stanton

4
L'utilisation findde la boucle extérieure n'est qu'une complication inutile. for i in */; do`
tripleee

fonction countit {pour i dans $ (find. -maxdepth 1 -type d); do file_count = $ (find $ i -type f | wc -l); echo "$ file_count: $ i"; terminé }; countit | sort -n -r
Schneems

Enfin, c'est ce dont j'avais besoin. Mes dossiers contiennent des milliers de fichiers, donc les imprimer avec un arbre ou quoi que ce soit d'autre n'est pas une option
lesolorzanov

Cela inclut ../ et ne semble pas aller de l'avant - ce qui signifie que ce n'est pas régressif.
Daniel Lefebvre

50

Vous pouvez utiliser

$ tree

après avoir installé le package d' arborescence avec

$ sudo apt-get install tree

(sur une machine Debian / Mint / Ubuntu Linux).

La commande affiche non seulement le nombre de fichiers, mais également le nombre de répertoires, séparément. L'option -L peut être utilisée pour spécifier le niveau d'affichage maximal (qui, par défaut, est la profondeur maximale de l'arborescence de répertoires).

Les fichiers cachés peuvent également être inclus en fournissant l' -aoption.


4
C'est en fait le moyen le plus simple de voir le nombre de répertoires et de fichiers.
Lorem Ipsum Dolor

11
Depuis la page de manuel: Par défaut, l'arborescence n'imprime pas les fichiers cachés . Vous devez fournir l' -aoption de les inclure.
eee

3
Pour l'installer sur macOS, utilisez brewet exécutez brew install tree, de préférence après l'exécution brew update.
Ashish Ahuja

4
Il imprime également tous les noms de fichiers, ce sera donc lent si vous avez plusieurs fichiers.
Franck Dernoncourt

2
Wow, très bel outil, il peut imprimer des dossiers colorisés, lister uniquement les dossiers, sortir en JSON. Il peut répertorier 34 000 dossiers et 51 000 fichiers en très peu de secondes. Olé!
brasofilo

46

Sur mon ordinateur, rsyncest un peu plus rapide que find | wc -ldans la réponse acceptée:

$ rsync --stats --dry-run -ax /path/to/dir /tmp

Number of files: 173076
Number of files transferred: 150481
Total file size: 8414946241 bytes
Total transferred file size: 8414932602 bytes

La deuxième ligne a le nombre de fichiers, 150 481 dans l'exemple ci-dessus. En bonus, vous obtenez également la taille totale (en octets).

Remarques:

  • la première ligne est un nombre de fichiers, répertoires, liens symboliques, etc. tous ensemble, c'est pourquoi elle est plus grande que la deuxième ligne.
  • le --dry-run(ou-n option pour faire court) est importante pour ne pas réellement transférer les fichiers!
  • J'ai utilisé l' -xoption "ne pas franchir les limites du système de fichiers", ce qui signifie que si vous l'exécutez pour /et que vous avez des disques durs externes connectés, il ne comptera que les fichiers sur la partition racine.

J'aime votre idée d'utiliser rsync ici. Je n'y aurais jamais pensé!
Qeole

Merci @Qeole, l'idée n'est pas la mienne cependant. Je l'ai lu il y a plusieurs années quelque part que rsync est le plus rapide pour supprimer un dossier avec beaucoup de fichiers et de sous-dossiers, j'ai donc pensé qu'il serait peut-être aussi rapide de compter les fichiers.
psmith

1
J'ai essayé ça. Après avoir exécuté les deux fois au préalable pour remplir le cache fs, il a find ~ -type f | wc -lfallu 1,7 / 0,5 / 1,33 seconde (réel / utilisateur / sys). rsync --stats --dry-run -ax ~ /xxxa pris 4,4 / 3,1 / 2,1 secondes. Cela représente environ 500 000 fichiers sur SSD.
slim

Vous ne savez pas quelle version de rsync vous avez utilisée, mais en 3.1.2 c'est un peu plus facile à lire:Number of files: 487 (reg: 295, dir: 192)
mpen

J'ai utilisé le rsync par défaut sur macOS:rsync version 2.6.9 protocol version 29
psmith

20

Étant donné que les noms de fichiers sous UNIX peuvent contenir des retours à la ligne (oui, les retours à la ligne), il wc -lpeut y avoir trop de fichiers. Je voudrais imprimer un point pour chaque fichier, puis compter les points:

find DIR_NAME -type f -printf "." | wc -c

1
On dirait que c'est la seule solution qui gère les fichiers avec des retours à la ligne dans leurs noms. A voté.
codeforester

2
hihi :) J'adore les nouvelles lignes dans les noms de fichiers. Cela les rend juste plus lisibles.
hek2mgl

Je veux dire, les nouvelles lignes dans les noms de fichiers et non le contenu!
codeforester

1
Je plaisantais juste ... Oui, les nouvelles lignes dans les noms de fichiers doivent toujours être prises en compte. Ils peuvent provenir de contenus malveillants ou moins spectaculaires, d'une faute de frappe.
hek2mgl

18

En combinant plusieurs des réponses ici ensemble, la solution la plus utile semble être:

find . -maxdepth 1 -type d -print0 |
xargs -0 -I {} sh -c 'echo -e $(find "{}" -printf "\n" | wc -l) "{}"' |
sort -n

Il peut gérer des choses étranges comme les noms de fichiers qui incluent des espaces entre parenthèses et même de nouvelles lignes. Il trie également la sortie en fonction du nombre de fichiers.

Vous pouvez augmenter le nombre après -maxdepthpour que les sous-répertoires soient également comptés. Gardez à l'esprit que cela peut potentiellement prendre beaucoup de temps, en particulier si vous avez une structure de répertoires hautement imbriquée en combinaison avec un -maxdepthnombre élevé .


Qu'est-ce que c'est echo -e? Je suppose que vous l'avez mis pour plier tous les retours à la ligne, mais il supprimera également tous les autres espaces irréguliers et tentera d'étendre tous les caractères génériques présents textuellement dans les noms de fichiers. J'irais simplement avec quelque chose comme find .* * -type d -execdir sh -c 'find . -type f -printf "\n" | wc -l; pwd'et vivrais avec toutes les aberrations dans la sortie, ou je jouerais peut-être avec Bash printf "%q"pour imprimer le nom du répertoire.
tripleee

10

Si vous voulez savoir combien de fichiers et de sous-répertoires existent dans le répertoire de travail actuel, vous pouvez utiliser ce one-liner

find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo -e $(find {} | wc -l) {}' | sort -n

Cela fonctionnera dans la saveur GNU, et omettra juste le -e de la commande echo pour BSD linux (par exemple OSX).


2
Excellente solution! Le seul problème que j'ai trouvé était les répertoires avec des espaces ou des caractères spéciaux. Ajoutez des guillemets où le nom du find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo -e $(find "{}" | wc -l) "{}"' | sort -n
John Kary

1
Je l'ai un peu modifié et cela fonctionne très bien pour moi:find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo $(find {} | wc -l) \\t {}' | sort -rn | less
Wizek

Mes commentaires sur la réponse de @ Sebastian s'appliquent également ici. L'utilisation de echo -e(ou simplement `echo` comme dans le commentaire précédent) sur un nom de répertoire non cité échange un problème contre un autre.
tripleee

8

Si vous voulez éviter les cas d'erreur, ne permettez pas wc -lde voir les fichiers avec des sauts de ligne (qui compteront comme 2+ fichiers)

Par exemple, considérons un cas où nous avons un seul fichier avec un seul caractère EOL

> mkdir emptydir && cd emptydir
> touch $'file with EOL(\n) character in it'
> find -type f
./file with EOL(?) character in it
> find -type f | wc -l
2

Puisqu'au moins gnu wcne semble pas avoir une option pour lire / compter une liste terminée par null (sauf à partir d'un fichier), la solution la plus simple serait simplement de ne pas lui passer les noms de fichiers, mais une sortie statique à chaque fois qu'un fichier est trouvé, par exemple dans le même répertoire que ci-dessus

> find -type f -exec printf '\n' \; | wc -l
1

Ou si votre findsoutien

> find -type f -printf '\n' | wc -l
1 

7

Vous pouvez utiliser la commande ncdu. Il comptera récursivement le nombre de fichiers contenus dans un répertoire Linux. Voici un exemple de sortie:

entrez la description de l'image ici

Il a une barre de progression, ce qui est pratique si vous avez plusieurs fichiers:

entrez la description de l'image ici

Pour l'installer sur Ubuntu:

sudo apt-get install -y ncdu

Benchmark: J'ai utilisé https://archive.org/details/cv_corpus_v1.tar (380390 fichiers, 11 Go) comme dossier où l'on doit compter le nombre de fichiers.

  • find . -type f | wc -l: environ 1m20 pour terminer
  • ncdu: environ 1m20 pour terminer

Cela calcule principalement l'utilisation du disque, pas le nombre de fichiers. Ce surcoût supplémentaire n'est probablement pas souhaité. (en plus de la nécessité d'installer un package supplémentaire pour quelque chose qui peut être fait avec les utilitaires POSIX standard)
hek2mgl

@ hek2mgl Il calcule le nombre de fichiers, comme indiqué en rouge dans la première capture d'écran. Cela m'a pris quelques minutes pour ~ 2 millions de fichiers, donc la vitesse n'est pas trop mauvaise.
Franck Dernoncourt

2
@ hek2mgl J'ai ajouté un point de repère reproductible dans la réponse, je l'ai exécuté deux fois et je n'ai vu aucune différence entre find . -type f | wc -let ncdu.
Franck Dernoncourt

2
oui, on dirait qu'il findest sous le capot exécutant plus ou moins les mêmes appels système que celui duqui est le backend ncdu. Je les ai juste étirés.
hek2mgl

1
@FranckDernoncourt a adoré. J'ai des tonnes de fichiers dans un dossier et avoir une barre de progression est un épargnant de vie. Merci d'avoir partagé!
Geek


4

Pour déterminer le nombre de fichiers dans le répertoire en cours, insérez-le ls -1 | wc -l. Cela permet wcde compter le nombre de lignes (-l)dans la sortie de ls -1. Il ne compte pas les fichiers dot. Veuillez noter quels -l (c'est un "L" plutôt qu'un "1" comme dans les exemples précédents) que j'ai utilisé dans les versions précédentes de ce HOWTO vous donnera en fait un nombre de fichiers supérieur de 1 au nombre réel. Merci à Kam Nejad pour ce point.

Si vous souhaitez compter uniquement les fichiers et ne pas inclure de liens symboliques (juste un exemple de ce que vous pourriez faire d'autre), vous pouvez utiliser ls -l | grep -v ^l | wc -l(c'est un "L" et non un "1" cette fois, nous voulons une liste "longue" ici) . grepvérifie toute ligne commençant par "l" (indiquant un lien) et supprime cette ligne (-v).

Vitesse relative: "ls -1 / usr / bin / | wc -l" prend environ 1,03 secondes sur un 486SX25 déchargé (/ usr / bin / sur cette machine contient 355 fichiers). "ls -l /usr/bin/ | grep -v ^l | wc -l " prend environ 1,19 seconde.

Source: http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x700.html


2
ls -ldoit faire statsyscall sur chaque fichier pour lire sa taille, mtime et d'autres propriétés, ce qui est lent. Sur les gros répertoires (plus de 100 000 fichiers), l'exécution ls -lpeut prendre plusieurs minutes. Donc, pour ne compter que les fichiers, utilisez toujours ls -1 | wc -l.
Marki555

A 486SX25, nice
cam8001

ls -1peut encore être lent dans les grands répertoires, car il doit trier les fichiers. Fait simplement printf '%s\n' *la même chose, et évite l' lsappel externe (ce qui est problématique de toute façon) mais la solution la plus efficace est d'utiliser une commande qui n'effectue aucun tri, comme find. (La sortie globale est triée par le shell.)
tripleee

4

Si vous avez besoin de compter récursivement un type de fichier spécifique , vous pouvez faire:

find YOUR_PATH -name '*.html' -type f | wc -l 

-l est juste d'afficher le nombre de lignes dans la sortie.


L'extension fait partie du nom de fichier et peut ne pas représenter le type de fichier
Waxhead

4

Avec bash:

Créez un tableau d'entrées avec () et obtenez le nombre avec #.

FILES=(./*); echo ${#FILES[@]}

Ok cela ne compte pas récursivement les fichiers mais je voulais d'abord montrer l'option simple. Un cas d'utilisation courant peut être la création de sauvegardes de substitution d'un fichier. Cela créera logfile.1, logfile.2, logfile.3 etc.

CNT=(./logfile*); mv logfile logfile.${#CNT[@]}

Nombre récursif avec bash 4+ globstaractivé (comme mentionné par @tripleee)

FILES=(**/*); echo ${#FILES[@]}

Pour obtenir le nombre de fichiers de manière récursive, nous pouvons toujours utiliser find de la même manière.

FILES=(`find . -type f`); echo ${#FILES[@]}

Les coquilles modernes prennent en charge l' **/*énumération récursive. C'est encore moins efficace que findsur les gros répertoires car le shell doit trier les fichiers dans chaque répertoire.
tripleee

2

J'ai écrit ffcnt pour accélérer le comptage récursif des fichiers dans des circonstances spécifiques: disques rotatifs et systèmes de fichiers qui prennent en charge le mappage d'étendue.

Il peut être un ordre de grandeur plus rapide que lsou findapproches fondées, mais YMMV.


2

Pour les répertoires avec des espaces dans le nom ... (sur la base des différentes réponses ci-dessus) - imprimer récursivement le nom du répertoire avec le nombre de fichiers dans:

find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done

Exemple (formaté pour la lisibilité):

pwd
  /mnt/Vancouver/Programming/scripts/claws/corpus

ls -l
  total 8
  drwxr-xr-x 2 victoria victoria 4096 Mar 28 15:02 'Catabolism - Autophagy; Phagosomes; Mitophagy'
  drwxr-xr-x 3 victoria victoria 4096 Mar 29 16:04 'Catabolism - Lysosomes'

ls 'Catabolism - Autophagy; Phagosomes; Mitophagy'/ | wc -l
  138

## 2 dir (one with 28 files; other with 1 file):
ls 'Catabolism - Lysosomes'/ | wc -l
  29

La structure du répertoire est mieux visualisée en utilisant tree:

tree -L 3 -F .
  .
  ├── Catabolism - Autophagy; Phagosomes; Mitophagy/
  │   ├── 1
  │   ├── 10
  │   ├── [ ... SNIP! (138 files, total) ... ]
  │   ├── 98
  │   └── 99
  └── Catabolism - Lysosomes/
      ├── 1
      ├── 10
      ├── [ ... SNIP! (28 files, total) ... ]
      ├── 8
      ├── 9
      └── aaa/
          └── bbb

  3 directories, 167 files

man find | grep mindep
  -mindepth levels
    Do not apply any tests or actions at levels less than levels
    (a non-negative integer).  -mindepth 1 means process all files
    except the starting-points.

ls -p | grep -v /(utilisé ci-dessous) provient de la réponse 2 sur /unix/48492/list-only-regular-files-but-not-directories-in-current-directory

find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done
./Catabolism - Autophagy; Phagosomes; Mitophagy: 138
./Catabolism - Lysosomes: 28
./Catabolism - Lysosomes/aaa: 1

Applcation: Je veux trouver le nombre maximum de fichiers parmi plusieurs centaines de répertoires (tous profondeur = 1) [sortie ci-dessous à nouveau formatée pour la lisibilité]:

date; pwd
    Fri Mar 29 20:08:08 PDT 2019
    /home/victoria/Mail/2_RESEARCH - NEWS

time find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done > ../../aaa
    0:00.03

[victoria@victoria 2_RESEARCH - NEWS]$ head -n5 ../../aaa
    ./RNA - Exosomes: 26
    ./Cellular Signaling - Receptors: 213
    ./Catabolism - Autophagy; Phagosomes; Mitophagy: 138
    ./Stress - Physiological, Cellular - General: 261
    ./Ancient DNA; Ancient Protein: 34

[victoria@victoria 2_RESEARCH - NEWS]$ sed -r 's/(^.*): ([0-9]{1,8}$)/\2: \1/g' ../../aaa | sort -V | (head; echo ''; tail)

    0: ./Genomics - Gene Drive
    1: ./Causality; Causal Relationships
    1: ./Cloning
    1: ./GenMAPP 2
    1: ./Pathway Interaction Database
    1: ./Wasps
    2: ./Cellular Signaling - Ras-MAPK Pathway
    2: ./Cell Death - Ferroptosis
    2: ./Diet - Apples
    2: ./Environment - Waste Management

    988: ./Genomics - PPM (Personalized & Precision Medicine)
    1113: ./Microbes - Pathogens, Parasites
    1418: ./Health - Female
    1420: ./Immunity, Inflammation - General
    1522: ./Science, Research - Miscellaneous
    1797: ./Genomics
    1910: ./Neuroscience, Neurobiology
    2740: ./Genomics - Functional
    3943: ./Cancer
    4375: ./Health - Disease 

sort -Vest une sorte naturelle. ... Donc, mon nombre maximum de fichiers dans l'un de ces répertoires (Claws Mail) est de 4375 fichiers. Si je laisse à gauche ( https://stackoverflow.com/a/55409116/1904943 ) ces noms de fichiers - ils sont tous nommés numériquement, en commençant par 1, dans chaque répertoire - et à 5 chiffres au total, je serais d'accord .


Addenda

Trouvez le nombre total de fichiers, sous-répertoires dans un répertoire.

$ date; pwd
Tue 14 May 2019 04:08:31 PM PDT
/home/victoria/Mail/2_RESEARCH - NEWS

$ ls | head; echo; ls | tail
Acoustics
Ageing
Ageing - Calorie (Dietary) Restriction
Ageing - Senescence
Agriculture, Aquaculture, Fisheries
Ancient DNA; Ancient Protein
Anthropology, Archaeology
Ants
Archaeology
ARO-Relevant Literature, News

Transcriptome - CAGE
Transcriptome - FISSEQ
Transcriptome - RNA-seq
Translational Science, Medicine
Transposons
USACEHR-Relevant Literature
Vaccines
Vision, Eyes, Sight
Wasps
Women in Science, Medicine

$ find . -type f | wc -l
70214    ## files

$ find . -type d | wc -l
417      ## subdirectories

0

Il existe de nombreuses réponses correctes ici. En voici un autre!

find . -type f | sort | uniq -w 10 -c

.est le dossier dans lequel rechercher et 10est le nombre de caractères permettant de regrouper le répertoire.


-1

trouver -type f | wc -l

OU (si le répertoire est le répertoire courant)

trouver . -type f | wc -l


Cela reproduit au moins une autre réponse à cette même question.
Kusalananda

-1

Cela fonctionnera parfaitement. Court simple. Si vous souhaitez compter le nombre de fichiers présents dans un dossier.

ls | wc -l

3
Tout d'abord, cela ne répond pas à la question. La question concerne le comptage récursif des fichiers d'un répertoire vers l'avant et la commande que vous affichez ne fait pas cela. de plus, avec ls vous comptez aussi bien les répertoires que les fichiers. De plus, il n'y a aucune raison de répondre à une ancienne question si vous ne voulez rien ajouter de nouveau et que vous n'allez même pas lire la question correctement. Veuillez vous abstenir de le faire.
XFCC

-1

Cette approche alternative avec filtrage pour le format compte tous les modules du noyau grub disponibles:

ls -l /boot/grub/*.mod | wc -l

-3
ls -l | grep -e -x -e -dr | wc -l 
  1. longue liste
  2. filtrer les fichiers et les répertoires
  3. compter la ligne filtrée non
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.