Recuento de archivos en cada subdirectorio

21

Me gustaría que un comando BASH enumere solo el recuento de archivos en cada subdirectorio de un directorio.

Por ejemplo, en el directorio /tmphay dir1, dir2... me gustaría ver:

`dir1` : x files 
`dir2` : x files ...
jldupont
fuente

Respuestas:

32

Suponiendo que desea un recuento recursivo de archivos solamente, no directorios y otros tipos, algo como esto debería funcionar:

find . -maxdepth 1 -mindepth 1 -type d | while read dir; do
  printf "%-25.25s : " "$dir"
  find "$dir" -type f | wc -l
done
Thor
fuente
Además, obtengo "find: warning: ha especificado la opción -maxdepth después de un tipo de argumento sin opción, pero las opciones no son posicionales (-maxdepth afecta las pruebas especificadas antes y las especificadas después). Especifique las opciones antes de otros argumentos ".
jldupont
2
Ambas respuestas dadas hasta ahora darán resultados incorrectos en el caso poco probable de que haya archivos cuyos nombres incluyan caracteres de nueva línea. Puedes manejar eso con un find... -print0 | xargs -0....
Scott
@jldupont: mueve los argumentos de profundidad antes del ´-type d´, he editado la respuesta.
Thor
¡Sí, y permítanme agregar la información de que esta excelente solución no tomará ninguna variable externa y, por lo tanto, funcionará bash alias!
syntaxerror
rápido, y tuberías sort -rn -k 2,2 -t$':'obtienes la lista DESC
Andre Figueiredo
14

Esta tarea me fascinó tanto que quería encontrar una solución yo mismo. Ni siquiera toma un ciclo while y PUEDE ser más rápido en velocidad de ejecución. No hace falta decir que los esfuerzos de Thor me ayudaron mucho a entender las cosas en detalle.

Así que aquí está el mío:

find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "{} : $(find "{}" -type f | wc -l)" file\(s\)' \;

Parece modesto por una razón, porque es mucho más poderoso de lo que parece. :-)

Sin embargo, si tiene la intención de incluir esto en su .bash_aliasesarchivo, debe verse así:

alias somealias='find . -maxdepth 1 -mindepth 1 -type d -exec sh -c '\''echo "{} : $(find "{}" -type f | wc -l)" file\(s\)'\'' \;'

Tenga en cuenta el manejo muy complicado de comillas simples anidadas . Y no, no es que no sea posible utilizar comillas dobles para el sh -cargumento.

error de sintaxis
fuente
Es más lento ya que invoca / bin / sh para cada directorio. Puedes verificar esto con strace -fc script. Su versión realiza aproximadamente un 70% más de llamadas al sistema. +1 para código más corto :-)
Thor
1
inspirado por esto; ordenado por conteo de archivos:find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "$(find "{}" -type f | wc -l)" {}' \; | sort -nr
mnagel
7
find . -type f | cut -d"/" -f2 | uniq -c

Enumera carpetas y archivos en la carpeta actual con un recuento de archivos que se encuentran debajo. OMI rápido y útil. (los archivos se muestran con el recuento 1).

no gracias
fuente
1
¿Qué tal una pequeña explicación de cómo está funcionando? :)
C0deDaedalus
1
¡genial gracias! Es posible que desee agregar | sort -rnpara ordenar subdirecciones por número de archivos.
Dennis Golomazov
1

Definitivamente, usar find es el camino a seguir si desea contar recursivamente, pero si solo desea contar los archivos directamente en un determinado directorio:

ls dir1 | wc -l

jrajav
fuente
No quiero hacer esto para cada uno de los 1000 de los directorios que tengo allí ...
jldupont
Luego usa xargs. ls -d */ | xargs -n1 ls | wc -l(Usar la respuesta que aceptar si ya funciona, aunque esto es sólo Y ahora usted sabe!.)
jrajav
su propuesta no mostró ningún resultado en muchos segundos, mientras que la respuesta que acepté sí.
jldupont
@jrajav este enfoque falla absolutamente para los directorios con espacios en blanco en ellos. Por eso findes tan importante. (y mucho menos , -print0y xargs -0ya lo señaló Scott en la otra respuesta)
syntaxerror
1
find . -mindepth 1 -type d -print0 | xargs -0 -I{} sh -c 'printf "%4d : %s\n" "$(find {} -type f | wc -l)" "{}"'

A menudo necesito contar la cantidad de archivos en mis subdirectorios y usar este comando. Prefiero que el recuento aparezca primero.

Teddy Katayama
fuente
0

Lo que uso ... Esto hace una matriz de todos los subdirectorios en el que da como parámetro. Imprima el subdirectorio y el recuento de ese mismo subdirectorio hasta que se procesen todos los subdirectorios.

#!/bin/bash    
directories=($(/bin/ls -l $1 | /bin/grep "^d" | /usr/bin/awk -F" " '{print $9}'))

for item in ${directories[*]}
    do
        if [ -d "$1$item" ]; then
            echo "$1$item"
            /bin/ls $1$item | /usr/bin/wc -l
        fi
    done
derberlinersmurf
fuente
0

Podrías usar este código de Python. Inicie el intérprete ejecutando python3y pegue esto:

folder_path = '.'
import os, glob
for folder in sorted(glob.glob('{}/*'.format(folder_path))):
    print('{:}: {:>8,}'.format(os.path.split(folder)[-1], len(glob.glob('{}/*'.format(folder)))))

O una versión recursiva para recuentos anidados:

import os, glob
def nested_count(folder_path, level=0):
    for folder in sorted(glob.glob('{}/'.format(os.path.join(folder_path, '*')))):
        print('{:}{:}: {:,}'.format('    '*level, os.path.split(os.path.split(folder)[-2])[-1], len(glob.glob(os.path.join(folder, '*')))))
        nested_count(folder, level+1)
nested_count('.')

Salida de ejemplo:

>>> figures: 5
>>> misc: 1
>>> notebooks: 5
>>>     archive: 65
>>>     html: 12
>>>     py: 12
>>>     src: 14
>>> reports: 1
>>>     content: 6
>>> src: 1
>>>     html_download: 1
AlexG
fuente