¿Cómo contar el número de archivos en cada directorio?


104

Puedo enumerar todos los directorios por

find ./ -type d

Intenté enumerar el contenido de cada directorio y contar el número de archivos en cada directorio usando el siguiente comando

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

Pero esto sumaba el número total de líneas devueltas por

find ./ -type d | xargs ls -l

¿Hay alguna manera de contar el número de archivos en cada directorio?


¿Está buscando una forma de contar el número de archivos en cada uno de los subdirectorios directamente debajo ./?
Tuxdude

5
¿Cómo es esta una pregunta fuera de tema? ¡Me gustaría ver los comentarios de los votantes cercanos con razón! Si esto está fuera de tema, ¿a dónde pertenece? superusuario? No lo creo ..
InfantPro'Aravind '

6
shell-script, batch-script están bajo el alcance de programación.
InfantPro'Aravind '

Estaba a punto de publicar la solución Pythonic, luego noté que la pregunta está cerrada.
anatoly techtonik

votó para reabrirlo. Puede haber otras respuestas que podrían ser útiles en muchas situaciones (incluida la programación de scripts, que es la razón por la que llegué a esta pregunta).
lepe

Respuestas:


110

Suponiendo que tiene GNU buscar, deje que busque los directorios y deje que bash haga el resto:

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

2
Es solo una versión ligeramente diferente de la anterior, así que: (pista: está ordenada por nombre y está en csv) para x in find . -maxdepth 1 -type d | sort; hacer y = find $x | wc -l; echo $ x, $ y; hecho
pcarvalho

5
¡Muy buena! Poniéndolo en una sola línea (para que sea cómodo para uso directo en shell):find . -type d -print0 | while read -d '' -r dir; do files=("$dir"/*); printf "%5d files in directory %s\n" "${#files[@]}" "$dir"; done
lucaferrario

13
Necesitaba obtener el número de todos los archivos (recursivamente contar) en cada subdirectorio. Esta modificación le da que: find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find $dir -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
OmidS

1
@Kory Lo siguiente lo hará:find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done | sort -rn -k1
OmidS

1
@OmidS Excelente delineador, pero $dirdebe estar entre comillas en su primer comentario para manejar correctamente los nombres de directorio con espacios en blanco. :find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
Radek Daniluk

183

Esto imprime el recuento de archivos por directorio para el nivel de directorio actual:

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

9
Con mucho, la mejor (y más elegante) solución si se quiere enumerar el número de archivos en directorios de nivel superior de forma recursiva.
itoctopus

13
Esto tiene dos problemas: cuenta un archivo por directorio más de lo que realmente hay y da una línea inútil que contiene el tamaño del directorio actual como "1 tamaño ". Ambos se pueden arreglar con du -a | sed '/.*\.\/.*\/.*/!d' | cut -d/ -f2 | sort | uniq -c. Agregar | sort -nrpara ordenar por el recuento en lugar del nombre del directorio.
postre

3
Me gustaría señalar que esto también funciona en OSX. (El simple hecho de copiar y pegar los consejos de Linux en un shell OSX generalmente no funciona.)
Pistos

2
obtiene un tamaño innecesario por du -a. La mejor manera es usar el comando buscar. pero la idea principal es exactamente la misma :)
Znik

5
encontrar . -tipo f | cut -d / -f2 | ordenar | uniq -c | sort -nr # corrige los problemas mencionados por el postre
jcomeau_ictx

28
find . -type f | cut -d/ -f2 | sort | uniq -c
  • find. -type f para encontrar todos los elementos del archivo de tipo
  • cut -d/ -f2 para recortar su carpeta específica
  • sort para ordenar la lista de nombres de carpetas
  • uniq -c para devolver el número de veces que se ha contado cada nombre de carpeta

8
¡Esto es mucho mejor que la respuesta aceptada, ya que obtiene un resumen de los directorios de nivel superior!
Jason Floyd

3
Esta debería ser la respuesta aceptada. Sencillo y comprensible.
xssChauhan

1
La mejor respuesta que debería aceptarse es esta.
loretoparisi

1
Sencillo, elegante y perfecto para mis necesidades.
RichR

Perfecto. Y puede extenderse para contar más de subdirectorios reemplazando los especificadores de campo con una lista de especificadores de campo. Por ejemplo:find . -type f | cut -d/ -f2,3 | sort | uniq -c
alga

15

Puede hacer arreglos para encontrar todos los archivos, eliminar los nombres de los archivos, dejando una línea que contenga solo el nombre del directorio para cada archivo, y luego contar el número de veces que aparece cada directorio:

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

El único problema en esto es si tiene algún nombre de archivo o nombre de directorio que contenga un carácter de nueva línea, lo cual es bastante improbable. Si realmente tiene que preocuparse por las nuevas líneas en los nombres de archivos o directorios, le sugiero que las encuentre y las arregle para que no contengan nuevas líneas (y persuadir silenciosamente a la parte culpable del error de sus formas).


Si está interesado en el recuento de archivos en cada subdirectorio del directorio actual, contando los archivos en cualquier subdirectorio junto con los archivos en el subdirectorio inmediato, adaptaría el sedcomando para imprimir solo el directorio de nivel superior:

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

El primer patrón captura el comienzo del nombre, el punto, la barra, el nombre hasta la siguiente barra y la barra, y reemplaza la línea con solo la primera parte, así:

./dir1/dir2/file1

es reemplazado por

./dir1/

El segundo reemplazo captura los archivos directamente en el directorio actual; no tienen una barra al final y se reemplazan por ./. La ordenación y el recuento funcionan solo con el número de nombres.


1
Esto no genera nombres de directorio que no contengan ningún archivo. No estoy seguro si esto es necesario.
Austin Phillips

Es cierto que no es así. No es particularmente trivial arreglarlo para hacerlo, ya que no se garantiza que los nombres de directorio vacíos aparezcan en la salida de find. Algunos podrían: si hay un archivo dir1/dir2/dir3/file1, pero dir1/dir2contiene solo subdirectorios (no archivos planos), entonces puede inferir su presencia. Pero si dir1/dir4no tiene archivos, su nombre simplemente no aparece.
Jonathan Leffler

Respuesta muy útil si solo desea ver los subdirectorios del directorio actual.
xixixao

Solo me detuve para dar las gracias. 3 años después de que se publicó esto, estaba buscando contar carpetas de segundo nivel por carpeta. Tu publicación me ahorró potencialmente muchas horas de jugar con sed, find y quién sabe qué más
Corvin

13

Aquí hay una forma de hacerlo, pero probablemente no sea la más eficiente.

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

Da un resultado como este, con el nombre del directorio seguido del recuento de entradas en ese directorio. Tenga en cuenta que el recuento de salida también incluirá las entradas del directorio que pueden no ser las que desea.

./c/fa/l:0
./a:4
./a/c:0
./a/a:1
./a/a/b:0

Parece muy caro de mantener 3 comandos ( bash, ls, wc) para cada directorio encontrado por find.
Jonathan Leffler

@JonathanLeffler De acuerdo, de ahí la primera línea de mi respuesta. Tu solución es mejor.
Austin Phillips

genial, esto es lo que estoy buscando, ¿puedo preguntar qué es el '-' al final?
una vez el

1
@once El - pertenece al comando bash que será generado por xargs. Desde man bash, A -- signals the end of options and disables further option processing. En este caso, evitaría que un archivo con nombre incorrecto encontrado como parte del hallazgo se convierta en parte del procesamiento de argumentos de bash.
Austin Phillips

8

La solución de todos los demás tiene un inconveniente u otro.

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

Explicación:

  • -type d: estamos interesados ​​en directorios.
  • -readable: Solo los queremos si es posible enumerar los archivos que contienen. Tenga en cuenta que findseguirá emitiendo un error cuando intente buscar más directorios en ellos, pero esto evita llamarlos -exec.
  • -exec sh -c BLAH sh {} ';': Para cada directorio, ejecute este fragmento de secuencia de comandos, con el $0conjunto de shy $1conjunto al nombre de archivo.
  • printf "%s " "$1": imprime de forma portátil y mínima el nombre del directorio, seguido de un espacio, no de una nueva línea.
  • ls -1UA: enumera los archivos, uno por línea, en orden de directorio (para evitar atascar la tubería), excluyendo solo los directorios especiales .y..
  • wc -l: cuenta las líneas

1
Modificación para mostrar los recuentos de archivos primero en la línea y ordenar por ellos:find -type d -readable -exec sh -c 'ls -1UA "$1" | wc -l | tr -d "\n" ; printf "\t%s\n" "$1" ' sh {} ';' | sort -n
Evgeni Sergeev

ejecuta shell muchas veces, luego es lento y utiliza muchos recursos.
Znik

6

Versión ligeramente modificada de la respuesta de Sebastian usando en findlugar de du(para excluir la sobrecarga relacionada con el tamaño del archivo que dudebe realizarse y que nunca se usa):

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

-mindepth 2El parámetro se usa para excluir archivos en el directorio actual. Si lo quita, verá un montón de líneas como las siguientes:

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

(muy parecido al du variante basada en)

Si también necesita contar los archivos en el directorio actual, use esta versión mejorada:

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

La salida será como la siguiente:

  234 dir1
  123 dir2
   42 .

5

Esto también se puede hacer recorriendo ls en lugar de buscar

for f in */; do echo "$f -> $(ls $f | wc -l)"; done

Explicación:

for f in */; - recorrer todos los directorios

do echo "$f -> - imprime el nombre de cada directorio

$(ls $f | wc -l) - llamar a ls para este directorio y contar líneas


1
Esto no funciona correctamente si los nombres de directorio contienen espacios en blanco.
Xylol

Pruebafor f ./* ; do echo $f $(ls "$f" | wc -l); done
4ndt3s

3

Esto debería devolver el nombre del directorio seguido del número de archivos en el directorio.

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

export -f findfiles

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

Salida de ejemplo:

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

El export -fes necesario porque el -execargumento de findno permite ejecutar una función bash a menos que invoques bash explícitamente, y necesitas exportar la función definida en el alcance actual al nuevo shell explícitamente.


Esto parece excesivamente complicado. También me parece que proporciona recuentos acumulativos para una jerarquía de directorios como ./dir1/dir2/dir3(contar los archivos dir1y sus subdirectorios todos juntos, en lugar de contar los archivos por dir1/dir2/dir3separado de los de dir1/dir2y ambos por separado de los de /dir1).
Jonathan Leffler

Entendí que eso era lo que quería el autor. Si ese no es el caso, estoy de acuerdo en que la respuesta no es relevante para la pregunta.
Tuxdude

1
@JonathanLeffler: de acuerdo, al leer la pregunta una vez más, me di cuenta de que tienes razón: he modificado la respuesta en consecuencia.
Tuxdude

2

Combiné la respuesta de Jackman @glenn y la respuesta de @ pcarvalho (en la lista de comentarios, hay algo mal con la respuesta de pcarvalho debido a que la función de control de toque de estilo de caracteres ' ` '(tilde)).

Mi script puede aceptar la ruta como un aumento y ordenar la lista de directorios como ls -l, también puede manejar el problema del "espacio en el nombre del archivo" .

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

Mi primera respuesta en stackoverflow, y espero que pueda ayudar a alguien ^ _ ^


1

encontrar . -type f -printf '% h \ n' | ordenar | uniq -c

da por ejemplo:

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

0

Intenté con algunos de los otros aquí, pero terminé con subcarpetas incluidas en el recuento de archivos cuando solo quería los archivos. Esto se imprime ./folder/path<tab>nnncon el número de archivos, sin incluir las subcarpetas, para cada subcarpeta de la carpeta actual.

for d in `find . -type d -print` 
do 
  echo -e "$d\t$(find $d -maxdepth 1 -type f -print | wc -l)"
done

0

Una forma sencilla de buscar archivos de un tipo determinado de forma recursiva. En este caso, archivos .jpg para todas las carpetas del directorio actual:

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


0

Un comando milagroso súper rápido, que atraviesa archivos de forma recursiva para contar la cantidad de imágenes en un directorio y organizar la salida por extensión de imagen:

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

Créditos: https://unix.stackexchange.com/a/386135/354980


0

Esta podría ser otra forma de navegar por las estructuras de directorio y proporcionar resultados detallados.

find . -type d  | awk '{print "echo -n \""$0"  \";ls -l "$0" | grep -v total | wc -l" }' | sh 

0

Edité el guión para excluir todos node_modules directorios dentro del analizado.

Esto se puede usar para verificar si el número de archivos del proyecto excede el número máximo que el observador de archivos puede manejar.

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

Para comprobar la cantidad máxima de archivos que puede ver su sistema:

cat /proc/sys/fs/inotify/max_user_watches

node_modules La carpeta debe agregarse a las rutas excluidas de su IDE / editor en sistemas lentos, y el recuento de otros archivos no debe exceder idealmente el máximo (aunque se puede cambiar).


-1

Esto le dará el recuento general.

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

No, no lo hará. Solo considerará un nivel de subdirectorios.
Kusalananda
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.