Найти топ-50 каталогов, содержащих наибольшее количество файлов / каталогов на их первом уровне?

21

Как я могу использовать findдля создания списка каталогов, которые содержат наибольшее количество файлов. Я бы хотел, чтобы список был от самого высокого до самого низкого. Я бы только хотел листинг идти на 1 уровень глубокой, и я обычно запускать эту команду из верхней части моей файловой системы, то есть /.

SLM
источник
Другой вопрос (на самом деле тот же, но заданный по-другому), но разве ответ не решит и ваш вопрос? unix.stackexchange.com/questions/117093/…
Патрик
Также связано - stackoverflow.com/questions/15216370/… . Именно на этом я основывал свой первоначальный ответ на вопросе об инодах, хотя я думаю, что мой подход предлагает некоторые улучшения по сравнению с теми, что там.
Грэм,
@Patrick - это загруженный Q только для того, чтобы разместить Грэма А. Правда, биты похоронены в других А, но это должно было вывести этот бит, чтобы на него можно было ссылаться в будущем.
СЛМ
@slm Тогда я действительно не понимаю, почему это не дубликат. Его ответ, кажется, является лишь разработкой ответа на другой вопрос. Итак, теперь у нас есть 3 вопроса на одно и то же. Я думаю, что ответ на мою ссылку тоже чище. Запуск оболочки для каждого найденного каталога просто кажется грязным.
Патрик
1
@ Патрик, я переработал ответ, чтобы решение GNU не запускало новую оболочку для каждого каталога. Обратите внимание, что это стандартное решение для переноса любого имени файла.
Грэм

Ответы:

17

Использование инструментов 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

Это использует две findкоманды. Первый находит каталоги и передает их в whileцикл, запускает следующий поиск для каждого каталога. Второй перечисляет все дочерние файлы / каталоги на первом уровне, в то время как grepсчитает их. grepПозволяет -print0использоваться со второй находкой , так как wcне имеет -zэквивалента. Это останавливает пересчет имен файлов с новой строкой дважды (хотя использование wcи не -print0будет иметь большого значения).

Результат второго findпомещается в аргумент, echoтак что имя каталога можно легко разместить в одной строке ( $(..)конструкция автоматически обрезает символ новой строки в конце grep). Затем строки сортируются по номеру, а 50 самых больших номеров отображаются с помощью head.

Обратите внимание, что это также будет включать в себя каталоги точек монтирования верхнего уровня. Простой способ обойти это - использовать связывание, а затем использовать каталог монтирования. Сделать это:

sudo mount --bind / /mnt

Более переносимое решение использует разные экземпляры оболочки для каждого каталога (также здесь дан ответ ):

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

Образец вывода:

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
Graeme
источник
11

ОБНОВЛЕНИЕ: я сделал все это ниже, что круто, но я придумал лучший способ сортировки каталогов по использованию inode:

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

И если вы хотите остаться в той же файловой системе, вы делаете:

du --inodes -xS

Вот пример выходных данных:

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

ТЕПЕРЬ С ЛС:

Несколько человек упомянули, что у них нет современных coreutils, и опция --inodes для них недоступна. Итак, вот ls:

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

Это дает мне почти идентичные результаты для 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:

Я думаю include, что все зависит от того, на какой каталог программа сначала смотрится - потому что они одинаковые и жестко связаны. Вроде как вещь выше. Хотя я могу ошибаться в этом - и я приветствую исправление ...

Основополагающий метод этого заключается в том, что я заменяю каждое из lsимен файлов на содержащее его имя каталога в sed.разделе «Далее» ... Ну, я сам немного нечеткий. Я вполне уверен, что он точно считает файлы, как вы можете видеть здесь:

% _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

Создайте тестовый каталог:

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

Некоторые детские каталоги:

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

Сделайте несколько файлов:

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

Некоторые жесткие ссылки:

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

Посмотрите на жесткие ссылки:

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

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

Они считаются в одиночку, но на один каталог вверх ...

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

Затем я запустил свой скрипт запуска снизу и:

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

И Грэм:

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

Так что я думаю, что это показывает, что единственный способ подсчитать inode - это inode. А поскольку подсчет файлов означает подсчет инодов, вы не можете вдвойне подсчитывать иноды - для точного подсчета файлов иноды не могут быть подсчитаны более одного раза.

OLD:

Я нахожу это быстрее, и это портативно:

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\}\)$/\1...\2/;p}'
CMD

Это не обязательно -execдля каждого каталога - он использует только один shпроцесс ell и один find. Я должен получить set -- $globправо по-прежнему включать .hiddenфайлы и все остальное, но это очень близко и очень быстро. Вы бы просто cdвошли в любой корневой каталог для проверки, и все готово.

Вот пример моего выходного прогона /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

Я также использую sedв нижней части, чтобы обрезать его до 50 лучших результатов. headбыло бы быстрее, конечно, но я также обрежу каждую строку при необходимости:

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

Правда, это грубо, но это была мысль. Другое использование я Неочищенный устройство сброса 2>stderrдля обоих findи cdв 2>/dev/null. Это просто чище, чем смотреть на ошибки прав доступа для каталогов, которые я не могу прочитать без доступа root - возможно, мне следует это указать find. Ну, это работа в процессе.

Итак, я исправил оболочки оболочки следующим образом:

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

На самом деле я собирался задать вопрос о том, как это можно сделать, но когда я печатал в заголовке вопроса, сайт указал мне на предложенный связанный вопрос, где, о чудо, Стефан уже взвешен . Так что это было удобно. Очевидно [^.],, что это хорошо поддерживается, но не переносимо, и вы должны использовать это, как !bang.я обнаружил в комментарии Стефана.

В любом случае, очевидно, что просто потянуть скрытые файлы было недостаточно. Поэтому мне придется setдважды, чтобы избежать поиска позиционеров для литерала $glob. Тем не менее, это, похоже, никак не влияет на производительность и надежно добавляет каждый файл в каталог.

Микесерв
источник
@Graeme Знаете, ни одно из наших решений не обрабатывает inode. Многие из тех файлов, которые мы перечисляем, вероятно, жестко связаны друг с другом. Я думаю, я мог бы сделать это с ls -iи ... я думаю ... возможно grep... возможно ... может быть ... ну, вы используете, -xdev,что является началом ... uniqи sort?
mikeserv
Какую версию duвы используете? Мой duне имеет --inodesвыбора.
Патрик
@ Патрик - возможно, хочу обновить - но я обновил пост.
mikeserv
Это отличная черта :-) Я бегу 8.21. Похоже, это было добавлено 2013-07-27
Патрик,
Кроме того, если вы не возражаете, не могли бы вы опубликовать это по этому вопросу . Я не думаю, что приму это, поскольку это не очень портативно, но я буду голосовать, и было бы хорошо иметь другое решение по этому вопросу.
Патрик
1

Почему бы не использовать что-то вроде KDirStat Хотя изначально он был написан для KDE, но он прекрасно работает и с GNOME, он дает вам лучшее представление о количестве файлов / dir и соответствующем использовании в GUI.

friendyogi
источник
1
Ищете метод командной строки.
SLM