Encontre os 50 principais diretórios contendo a maioria dos arquivos / diretórios em seu primeiro nível?

16

Como posso usar find para gerar uma lista de diretórios que contenham o maior número de arquivos. Eu gostaria que a lista fosse do maior para o menor. Eu gostaria apenas que a listagem fosse de 1 nível de profundidade, e eu normalmente executaria esse comando do topo do meu sistema de arquivos, ou seja, / .

    
por slm 03.04.2014 / 03:43

3 respostas

13

Usando ferramentas GNU:

find / -xdev -type d -print0 |
  while IFS= read -d '' dir; do
    echo "$(find "$dir" -maxdepth 1 -print0 | grep -zc .) $dir"
  done |
  sort -rn |
  head -50

Isso usa dois comandos find . O primeiro encontra diretórios e os canaliza para um while loop executa o próximo find para cada diretório. O segundo lista todos os arquivos / diretórios filhos no primeiro nível, enquanto grep os conta. O grep permite que -print0 seja usado com o segundo achado, pois wc não possui um -z equivalente. Isso impede que nomes de arquivos com uma nova linha sejam contados duas vezes (embora usar wc e não -print0 não faria muita diferença).

O resultado do segundo find é colocado no argumento para echo , portanto, e o nome do diretório pode ser facilmente colocado na mesma linha (a construção $(..) apara automaticamente a nova linha no final de grep ). As linhas são classificadas por número e os 50 maiores números mostrados com head .

Observe que isso também incluirá os diretórios de nível superior dos pontos de montagem. Uma maneira simples de contornar isso é usar uma montagem de ligação e, em seguida, usar o diretório da montagem. Para fazer isso:

sudo mount --bind / /mnt

Uma solução mais portátil usa uma instância de shell diferente para cada diretório (também respondida aqui ):

find / -xdev -type d -exec sh -c '
  echo "$(find "$0" | grep "^$0/[^/]*$" | wc -l) $0"' {} \; |
  sort -rn |
  head -50

Saída de amostra:

9225 /var/lib/dpkg/info
6322 /usr/share/qt4/doc/html
4927 /usr/share/man/man3
2301 /usr/share/man/man1
2097 /usr/share/doc
2097 /usr/bin
1863 /usr/lib/x86_64-linux-gnu
1679 /var/cache/apt/archives
1628 /usr/share/qt4/doc/src/images
1614 /usr/share/qt4/doc/html/images
1308 /usr/share/scilab/modules/overloading/macros
1083 /usr/src/linux-headers-3.13-1-common/include/linux
1071 /usr/src/linux-headers-3.13-1-amd64/include/config
847 /usr/include/qt4/QtGui
774 /usr/include/qt4/Qt
709 /usr/share/man/man8
616 /usr/lib
611 /usr/share/icons/oxygen/32x32/actions
608 /usr/share/icons/oxygen/22x22/actions
598 /usr/share/icons/oxygen/16x16/actions
579 /usr/share/bash-completion/completions
574 /usr/share/icons/oxygen/48x48/actions
570 /usr/share/vim/vim74/syntax
546 /usr/share/scilab/modules/m2sci/macros/sci_files
531 /usr/lib/i386-linux-gnu/wine/wine
530 /usr/lib/i386-linux-gnu/wine/wine/fakedlls
496 /etc/ssl/certs
457 /usr/share/mime/application
454 /usr/share/man/man2
450 /usr/include/qt4/QtCore
443 /usr/lib/python2.7
419 /usr/src/linux-headers-3.13-1-common/include/uapi/linux
413 /usr/share/fonts/X11/misc
413 /usr/include/linux
375 /usr/share/man/man5
374 /usr/share/lintian/overrides
372 /usr/share/cmake-2.8/Modules
370 /usr/share/fonts/X11/75dpi
370 /usr/share/fonts/X11/100dpi
356 /usr/share/icons/gnome/24x24/actions
356 /usr/share/icons/gnome/22x22/actions
356 /usr/share/icons/gnome/16x16/actions
353 /usr/share/icons/gnome/48x48/actions
353 /usr/share/icons/gnome/32x32/actions
341 /usr/lib/ghc/ghc-7.6.3
326 /usr/sbin
324 /usr/share/scilab/modules/compatibility_functions/macros
324 /usr/share/scilab/modules/cacsd/macros
320 /usr/share/terminfo/a
319 /usr/share/i18n/locales
    
por 03.04.2014 / 03:44
7

UPDATE: Eu fiz tudo isso abaixo, o que é legal, mas eu criei uma maneira melhor de classificar os diretórios pelo uso do inode:

du --inodes -S | sort -rh | sed -n \
        '1,50{/^.\{71\}/s/^\(.\{30\}\).*\(.\{37\}\)$/.../;p}'

E se você quiser ficar no mesmo sistema de arquivos que você:

du --inodes -xS

Veja alguns exemplos de saída:

15K     /usr/share/man/man3
4.0K    /usr/lib
3.6K    /usr/bin
2.4K    /usr/share/man/man1
1.9K    /usr/share/fonts/75dpi
...
519     /usr/lib/python2.7/site-packages/bzrlib
516     /usr/include/KDE
498     /usr/include/qt/QtCore
487     /usr/lib/modules/3.13.6-2-MANJARO/build/include/config
484     /usr/src/linux-3.12.14-2-MANJARO/include/config

AGORA COM LS:

Várias pessoas mencionaram que não têm coreutils atualizados e a opção --inodes não está disponível para eles. Então, aqui está o ls:

sudo ls -AiR1U ./ | 
sed -rn '/^[./]/{h;n;};G;
    s|^ *([0-9][0-9]*)[^0-9][^/]*([~./].*):|:|p' | 
sort -t : -uk1.1,1n |
cut -d: -f2 | sort -V |
uniq -c |sort -rn | head -n10

Isso está me fornecendo resultados praticamente idênticos ao comando du :

DU:

15K     /usr/share/man/man3
4.0K    /usr/lib
3.6K    /usr/bin
2.4K    /usr/share/man/man1
1.9K    /usr/share/fonts/75dpi
1.9K    /usr/share/fonts/100dpi
1.9K    /usr/share/doc/arch-wiki-markdown
1.6K    /usr/share/fonts/TTF
1.6K    /usr/share/dolphin-emu/sys/GameSettings
1.6K    /usr/share/doc/efl/html

LS:

14686   /usr/share/man/man3:
4322    /usr/lib:
3653    /usr/bin:
2457    /usr/share/man/man1:
1897    /usr/share/fonts/100dpi:
1897    /usr/share/fonts/75dpi:
1890    /usr/share/doc/arch-wiki-markdown:
1613    /usr/include:
1575    /usr/share/doc/efl/html:
1556    /usr/share/dolphin-emu/sys/GameSettings:

Eu acho que a coisa include depende apenas do diretório que o programa olha primeiro - porque eles são os mesmos arquivos e hardlinked. Meio como a coisa acima. Eu posso estar errado sobre isso - e agradeço a correção ...

O método subjacente para isso é que eu substituo cada um dos nomes de arquivos de ls pelo seu nome de diretório contendo em sed. . Daqui em diante ... Bem, eu mesmo sou um pouco confuso. Tenho certeza de que está contando os arquivos com precisão, como você pode ver aqui:

% _ls_i ~/test
> 100 /home/mikeserv/test/realdir
>   2 /home/mikeserv/test
>   1 /home/mikeserv/test/linkdir

DU DEMO

% du --version
> du (GNU coreutils) 8.22

Crie um diretório de teste:

% mkdir ~/test ; cd ~/test
% du --inodes -S
> 1       .

Alguns diretórios de crianças:

% mkdir ./realdir ./linkdir
% du --inodes -S
> 1       ./realdir
> 1       ./linkdir
> 1       .

Crie alguns arquivos:

% printf 'touch ./realdir/file%s\n' 'seq 1 100' | . /dev/stdin
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

Alguns hardlinks:

% printf 'n="%s" ; ln ./realdir/file$n ./linkdir/link$n\n' 'seq 1 100' | 
    . /dev/stdin
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

Veja os hardlinks:

% cd ./linkdir
% du --inodes -S
> 101

% cd ../realdir
% du --inodes -S
> 101

Eles são contados sozinhos, mas vão até um diretório ...

% cd ..
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

Em seguida, executei meu script de execução abaixo e:

> 100     /home/mikeserv/test/realdir
> 100     /home/mikeserv/test/linkdir
> 2       /home/mikeserv/test

E Graeme:

> 101 ./realdir
> 101 ./linkdir
> 3 ./

Então, acho que isso mostra que a única maneira de contar inodes é por inode. E como contar arquivos significa contar inodes, você não pode contar duplamente inodes - para contar arquivos com precisão, os inodes não podem ser contados mais de uma vez.

OLD:

Acho isso mais rápido e portátil:

sh <<-\CMD
    { echo 'here='"$PWD"
        printf 'cd "${here}/%s" 2>/dev/null && {
                set -- 
                for glob in ".[!.]*" "[!.]*" ; do
                    set -- $glob "$@" && 
                        [ -e "./$1" ] || shift
                done    
                printf "%%s\t%%s\n" $# "$PWD"
        }\n' $( find . -depth -type d 2>/dev/null )
    } | . /dev/stdin |
    sort -rn | 
    sed -n \
        '1,50{/^.\{71\}/s/^\(.\{30\}\).*\(.\{37\}\)$/.../;p}'
CMD

Ele não precisa de -exec para cada diretório - ele usa apenas o processo sh ell e um find . Eu tenho que ter o set -- $glob direito ainda para incluir arquivos .hidden e tudo mais, mas é muito próximo e muito rápido. Você iria apenas cd em qualquer que seja seu diretório raiz para o check e pronto.

Aqui está uma amostra da minha execução de saída de /usr :

14684   /usr/share/man/man3
4322    /usr/lib
3650    /usr/bin
2454    /usr/share/man/man1
1897    /usr/share/fonts/75dpi
...
557     /usr/share/gtk-doc/html/gtk3
557     /usr/share/doc/elementary/latex
539     /usr/lib32/wine/fakedlls
534     /usr/lib/python2.7/site-packages/bzrlib
500     /usr/lib/python3.3/test

Eu também uso sed na parte inferior para apará-lo nos 50 melhores resultados. head seria mais rápido, é claro, mas eu também aparo cada linha se necessário:

...   
159     /home/mikeserv/.config/hom...hhkdoolnlbekcfllmednbl/4.30_0/plugins
154     /home/mikeserv/.config/hom...odhpcledpamjachpmelml/1.3.11_0/js/ace
...

É bruto, reconhecidamente, mas foi um pensamento. Outro dispositivo bruto que uso está jogando 2>stderr para find e cd em 2>/dev/null . É apenas mais limpo do que olhar para erros de permissão para diretórios que não consigo ler sem acesso root - talvez eu deva especificar isso para find . Bem, é um trabalho em andamento.

Ok, então corrijo os globos da shell assim:

for glob in ".[!.]*" "[!.]*" ; do
    set -- $glob "$@" && 
        [ -e "./$1" ] || shift
done    

Eu realmente ia fazer uma pergunta sobre como isso poderia ser feito, mas como eu estava digitando no título da questão, o site me apontou para um sugeriu uma questão relacionada onde eis que Stephane já tinha pesado em . Então isso foi conveniente. Aparentemente, [^.], , embora bem suportado, é não portátil e você tem que usar o !bang. que eu encontrei no comentário de Stephane lá.

De qualquer forma, apenas puxar arquivos ocultos não era suficiente, obviamente. Então eu tenho que set duas vezes para evitar a procura de posições para o literal $glob . Ainda assim, não parece afetar o desempenho, e adiciona de forma confiável todos os arquivos no diretório.

    
por 13.04.2017 / 14:36
0

Por que não usar algo como o KDirStat? Embora tenha sido originalmente escrito para o KDE, mas funciona bem com o GNOME Dá-lhe a melhor visão do número de arquivo / dir e respectivo uso na GUI

    
por 03.04.2014 / 21:07

Tags