Contagem de arquivos em cada subdiretório

21

Eu gostaria que um comando BASH listasse apenas a contagem de arquivos em cada subdiretório de um diretório.

Por exemplo, no diretório /tmpnão são dir1, dir2, ... Eu gostaria de ver:

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

Respostas:

32

Supondo que você queira apenas uma contagem recursiva de arquivos, não diretórios e outros tipos, algo como isso deve funcionar:

find . -maxdepth 1 -mindepth 1 -type d | while read dir; do
  printf "%-25.25s : " "$dir"
  find "$dir" -type f | wc -l
done
Thor
fonte
Além disso, recebo "find: warning: você especificou a opção -maxdepth após um argumento não-option -type, mas as opções não são posicionais (-maxdepth afeta os testes especificados antes e os especificados depois). Especifique as opções antes de outros argumentos ".
Jdupont #
2
As duas respostas fornecidas até o momento fornecerão resultados incorretos no caso improvável de que haja arquivos cujos nomes incluam caracteres de nova linha. Você pode lidar com isso com um find... -print0 | xargs -0....
Scott
@ jldupont: mova os argumentos de profundidade antes do tipo 'd', editei a resposta.
Thor
Sim, e deixe-me acrescentar as informações de que esta excelente solução não aceita variáveis externas e, portanto, funcionará com bash alias!!
Syntaxerror # 25/14
rápido, e tubulação sort -rn -k 2,2 -t$':'você obterá a lista DESC
Andre Figueiredo
14

Essa tarefa me fascinou tanto que eu mesma queria descobrir uma solução. Nem sequer demora um loop e PODE ser mais rápido na velocidade de execução. Escusado será dizer que os esforços de Thor me ajudaram muito a entender as coisas em detalhes.

Então aqui está o meu:

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

Parece modesto por um motivo, pois é muito mais poderoso do que parece. :-)

No entanto, se você pretende incluir isso em seu .bash_aliasesarquivo, ele deve se parecer com o seguinte:

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

Observe o tratamento muito complicado de aspas simples aninhadas . E não, é não possível usar aspas duplas para o sh -cargumento.

erro de sintaxe
fonte
É mais lento, pois invoca / bin / sh para cada diretório. Você pode verificar isso com strace -fc script. Sua versão faz cerca de 70% mais chamadas de sistema. +1 para o código mais curto :-)
Thor
11
inspirado por isso; ordenado por contagem de arquivos:find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "$(find "{}" -type f | wc -l)" {}' \; | sort -nr
mnagel 21/03
7
find . -type f | cut -d"/" -f2 | uniq -c

Lista pastas e arquivos na pasta atual com uma contagem de arquivos encontrados abaixo. IMO rápido e útil. (os arquivos são exibidos com a contagem 1).

nothx
fonte
11
Que tal uma pequena explicação de como está funcionando? :)
C0deDaedalus
11
incrível, obrigado! Você pode querer adicionar | sort -rnpara ordenar subdiretórios por número de arquivos.
Dennis Golomazov 18/09/19
1

O uso de find é definitivamente o caminho a percorrer se você deseja contar recursivamente, mas se deseja apenas uma contagem dos arquivos diretamente em um determinado diretório:

ls dir1 | wc -l

jrajav
fonte
Eu não quero fazer isso para cada um dos 1000 de diretórios que eu tenho lá ...
jldupont
Então use xargs. ls -d */ | xargs -n1 ls | wc -l(Use a resposta que você aceite se já funciona, embora Este é apenas e agora você sabe!).
jrajav
sua proposta não apresentou resultados em muitos segundos, enquanto a resposta que aceitei apareceu.
precisa saber é o seguinte
@jrajav essa abordagem absolutamente falha em diretórios com espaços em branco. É por findisso que é tão importante. (muito menos -print0e xargs -0, já apontado por Scott na outra resposta)
SyntaxError
1
find . -mindepth 1 -type d -print0 | xargs -0 -I{} sh -c 'printf "%4d : %s\n" "$(find {} -type f | wc -l)" "{}"'

Muitas vezes, preciso contar o número de arquivos nos meus subdiretórios e usar este comando. Prefiro que a contagem apareça primeiro.

Teddy Katayama
fonte
0

O que eu uso ... Isso cria uma matriz de todos os subdiretórios na que você fornece como parâmetro. Imprima o subdiretório e a contagem desse mesmo subdiretório até que todos os subdiretórios sejam processados.

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

Você pode usar esse código python. Inicialize o intérprete executando python3e cole este:

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)))))

Ou uma versão recursiva para contagens aninhadas:

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('.')

Exemplo de saída:

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