statistiques récursives sur les types de fichiers dans le répertoire?

65

J'ai créé un site Web pour un projet de conversion. J'aimerais faire quelques statistiques sur les types de fichiers qu'il contient - par exemple, 400 .html, 100 .gif, etc. Quel est le moyen le plus simple de procéder? Il faut que ce soit récursif.

Edit: Avec le script que maxschelpzig a posté, je rencontre quelques problèmes en raison de l'architecture du site que j'ai effacé. Certains des fichiers portent des noms *.php?blah=blah&foo=baravec des arguments différents, ils sont donc tous considérés comme uniques. La solution doit donc être considérée comme *.php*étant du même type, pour ainsi dire.

utilisateur394
la source

Réponses:

96

Vous pouvez utiliser findet uniqpour cela, par exemple:

$ find . -type f | sed 's/.*\.//' | sort | uniq -c
   16 avi
   29 jpg
  136 mp3
    3 mp4

Explication de commande

  • find affiche récursivement tous les noms de fichiers
  • sed supprime de chaque nom de fichier le préfixe jusqu'à l'extension du fichier
  • uniq assume l'entrée triée
    • -c fait le comptage (comme un histogramme).
maxschlepzig
la source
J'ai un script similaire. Simple et rapide
Rufo El Magufo
Certains des fichiers portent des noms *.php?blah=blah&foo=baravec des arguments différents, ils sont donc tous considérés comme uniques. Comment puis-je le modifier pour chercher *.php*?
user394
3
Vous pouvez essayer d’utiliser une autre expression sed, par exemplesed 's/^.*\(\.[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]\).*$/\1/'
maxschlepzig
Merci d'avoir pris le temps d'expliquer ce que chaque partie fait. Tant de réponses sur des sujets similaires sautent cette partie. / apprendre à pêcher
MechEthan
1
@ bela83, les variantes d'élagage reposent sur une évaluation de court-circuit . Ainsi, ma première version est find -name '.*' -prune -o -type f -printévaluée comme suit : si l'entrée du répertoire correspond, .*alors l'élaguer, sinon s'il s'agit d'un fichier, imprimez-le. Comme les .*correspondances ., c’est-à-dire le CWD, tout est élagué, c’est-à-dire que find ne descend même pas dans le premier répertoire. Peut-être que les versions de 2 ans de findse comportaient différemment - ou que c'était juste un oubli de moi à l'époque. Quoi qu'il en soit, find -name '.*' -not -name . -prune -o -type f -printcorrige cela.
maxschlepzig
6

Avec zsh:

print -rl -- **/?*.*(D.:e) | uniq -c |sort -n

Le modèle **/?*.* correspond à tous les fichiers ayant une extension, dans le répertoire en cours et ses sous-répertoires de manière récursive. Le qualificatif glob D laisse zshparcourir les répertoires même cachés et considère les fichiers cachés, .ne sélectionne que les fichiers normaux. Le modificateur d'historique ne conserve que l'extension de fichier. print -rlimprime une correspondance par ligne. uniq -ccompte les éléments identiques consécutifs (le résultat global est déjà trié). Le dernier appel pour sorttrier les extensions par nombre d'utilisations.

Gilles, arrête de faire le mal
la source
5

Ce one-liner semble être une méthode assez robuste:

find . -type f -printf '%f\n' | sed -r -n 's/.+(\..*)$/\1/p' | sort | uniq -c

Les find . -type f -printf '%f\n'impressions du BaseName de chaque fichier régulier dans l'arborescence, sans répertoires. Cela vous évite d'avoir à vous soucier des répertoires qui pourraient s'y trouver .dans votre sedregex.

Le sed -r -n 's/.+(\..*)$/\1/p'remplace le nom de fichier entrant par uniquement son extension. Par exemple, .somefile.extdevient .ext. Notez l'initiale .+dans la regex; il en résulte que toute correspondance nécessitant au moins un caractère avant l'extension .. Cela évite que les noms de fichiers comme .gitignoreétant sans nom et l'extension '.gitignore', ce que vous voulez probablement. Sinon, remplacez le .+par un .*.

Le reste de la ligne provient de la réponse acceptée.

Edit : Si vous voulez un histogramme bien trié au format graphique de Pareto , ajoutez-en un autre sortà la fin:

find . -type f -printf '%f\n' | sed -r -n 's/.+(\..*)$/\1/p' | sort | uniq -c | sort -bn

Exemple de sortie d'une arborescence source Linux construite:

    1 .1992-1997
    1 .1994-2004
    1 .1995-2002
    1 .1996-2002
    1 .ac
    1 .act2000
    1 .AddingFirmware
    1 .AdvancedTopics
    [...]
 1445 .S
 2826 .o
 2919 .cmd
 3531 .txt
19290 .h
23480 .c
Gary R. Van Sickle
la source
1

J'ai mis un script bash dans mon ~/bindossier appelé exhistavec ce contenu:

#!/bin/bash

for d in */ ; do
        echo $d
        find $d -type f | sed -r 's/.*\/([^\/]+)/\1/' | sed 's/^[^\.]*$//' | sed -r 's/.*(\.[^\.]+)$/\1/' | sort | uniq -c | sort -nr
#       files only      | keep filename only          | no ext -> '' ext   | keep part after . (i.e. ext) | count          | sort by count desc
done

Quel que soit le répertoire dans lequel je me trouve, je tape simplement «exh», l'onglet le complète automatiquement et je vois à peu près ceci:

$ exhist
src/
      7 .java
      1 .txt
target/
     42 .html
     10 .class
      4 .jar
      3 .lst
      2 
      1 .xml
      1 .txt
      1 .properties
      1 .js
      1 .css

PS Couper la partie après le point d'interrogation devrait être simple à faire avec une autre commande sed probablement après la dernière (je ne l'ai pas essayée): sed 's/\?.*//'

Zsolt Katona
la source