estadísticas recursivas sobre los tipos de archivos en el directorio?

65

Hice un raspado de sitio web para un proyecto de conversión. Me gustaría hacer algunas estadísticas sobre los tipos de archivos allí, por ejemplo, 400 .htmlarchivos, 100 .gif, etc. ¿Cuál es una manera fácil de hacer esto? Tiene que ser recursivo.

Editar: con el script que publicó maxschelpzig, tengo algunos problemas debido a la arquitectura del sitio que he eliminado. Algunos de los archivos son del nombre *.php?blah=blah&foo=barcon varios argumentos, por lo que los cuenta a todos como únicos. Por lo tanto, la solución debe considerarse *.php*del mismo tipo, por así decirlo.

usuario394
fuente

Respuestas:

96

Puede usar findy uniqpara esto, por ejemplo:

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

Explicación del comando

  • find imprime recursivamente todos los nombres de archivo
  • sed elimina de cada nombre de archivo el prefijo hasta la extensión del archivo
  • uniq asume una entrada ordenada
    • -c hace el conteo (como un histograma).
maxschlepzig
fuente
Tengo un guión similar. Simple y rapido.
Rufo El Magufo
Algunos de los archivos son del nombre *.php?blah=blah&foo=barcon varios argumentos, por lo que los cuenta a todos como únicos. ¿Cómo puedo modificarlo para buscarlo *.php*?
user394
3
Puede intentar usar una expresión sed diferente, por ejemplosed 's/^.*\(\.[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]\).*$/\1/'
maxschlepzig
Gracias por tomarse el tiempo para explicar lo que hace cada porción. Tantas respuestas sobre temas similares se saltan esta parte. / learning-to-fish
MechEthan
1
@ bela83, las variantes de poda dependen de la evaluación de cortocircuito ; por lo tanto, mi primera versión se find -name '.*' -prune -o -type f -printevalúa como: si la entrada del directorio coincide .*, podarla; de lo contrario, si es un archivo, imprimirlo. Como .*también coincide ., es decir, el CWD, todo se poda, es decir, find ni siquiera desciende al primer directorio. Tal vez, las versiones de 2 años de edad se findcomportaron de manera diferente, o era solo un descuido de mí, en aquel entonces. De todos modos, find -name '.*' -not -name . -prune -o -type f -printarregla esto.
maxschlepzig
6

Con zsh:

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

El patrón **/?*.* coincide con todos los archivos que tienen una extensión, en el directorio actual y sus subdirectorios de forma recursiva. El calificador global D permite zshrecorrer incluso directorios ocultos y considerar archivos ocultos, .selecciona solo archivos normales. El modificador de historial conserva solo la extensión del archivo. print -rlimprime una coincidencia por línea. uniq -ccuenta elementos idénticos consecutivos (el resultado global ya está ordenado). La última llamada para sortordenar las extensiones por conteo de uso.

Gilles 'SO- deja de ser malvado'
fuente
5

Este one-liner parece ser un método bastante robusto:

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

Los find . -type f -printf '%f\n'grabados el nombre base de cada archivo normal en el árbol, sin directorios. Eso elimina tener que preocuparse por los directorios que pueden tener .en ellos en su sedexpresión regular.

El sed -r -n 's/.+(\..*)$/\1/p'reemplaza el nombre de archivo entrante con solo su extensión. Por ejemplo, se .somefile.extconvierte .ext. Tenga .+en cuenta la inicial en la expresión regular; Esto hace que cualquier coincidencia necesite al menos un carácter antes de la extensión .. Esto evita que los nombres de archivo .gitignoresean tratados como sin nombre y con la extensión '.gitignore', que es probablemente lo que desea. Si no, reemplace el .+con a .*.

El resto de la línea es de la respuesta aceptada.

Editar : si desea un histograma bien ordenado en formato de gráfico de Pareto , simplemente agregue otro sortal final:

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

Salida de muestra de un árbol fuente Linux construido:

    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
fuente
1

Puse un script bash en mi ~/bincarpeta llamada exhistcon este contenido:

#!/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

En cualquier directorio en el que me encuentre, simplemente escribo 'exh', la pestaña lo completa automáticamente y veo algo como esto:

$ 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 Recortar la parte después del signo de interrogación debería ser simple de hacer con otro comando sed probablemente después del último (no lo he probado): sed 's/\?.*//'

Zsolt Katona
fuente