Znajdź 50 najlepszych katalogów zawierających najwięcej plików / katalogów na pierwszym poziomie?

21

Jak mogę użyć finddo wygenerowania listy katalogów, które zawierają największą liczbę plików. Chciałbym, aby lista była od najwyższej do najniższej. Chciałbym tylko, aby lista sięgała 1 poziomu w głąb i zwykle uruchamiałam to polecenie z góry mojego systemu plików, tj /.

slm
źródło
Inne pytanie (właściwie to samo, ale zadane inaczej), ale czy odpowiedź również nie rozwiąże twojego pytania? unix.stackexchange.com/questions/117093/…
Patrick
Powiązane również - stackoverflow.com/questions/15216370/… . Właśnie dlatego oparłem moją pierwotną odpowiedź na pytaniu o i-węzeł, chociaż myślę, że moje podejście oferuje pewne ulepszenia w stosunku do tamtych.
Graeme,
@Patrick - jest to załadowane Q tylko do przechowywania Graemes A. To prawda, że ​​bity są zakopane w pozostałych Q's A, ale miało to na celu wydobycie tego bitu, aby można było do niego odwołać się w przyszłości.
slm
@slm Więc naprawdę nie rozumiem, dlaczego to nie jest duplikat. Jego odpowiedź wydaje się być rozwinięciem odpowiedzi na inne pytanie. Mamy teraz 3 pytania dotyczące tego samego. Myślę, że odpowiedź na mój link też jest czystsza. Uruchomienie powłoki dla każdego znalezionego katalogu jest po prostu brudne.
Patrick,
1
@Patrick, przerobiłem odpowiedź, aby rozwiązanie GNU nie uruchamiało nowej powłoki dla każdego katalogu. Należy jednak pamiętać, że jest to standardowe rozwiązanie umożliwiające przenośne zarządzanie dowolnymi nazwami plików.
Graeme,

Odpowiedzi:

17

Za pomocą narzędzi 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

To używa dwóch findpoleceń. Pierwszy znajdzie katalogi i potokuje je do whilepętli, a następnie uruchomi kolejne wyszukiwanie dla każdego katalogu. Drugi wyświetla wszystkie pliki / katalogi potomne na pierwszym poziomie, jednocześnie grepje licząc. grepPozwala -print0być stosowany z drugim znalezisku ponieważ wcnie ma -zodpowiednika. Zapobiega to dwukrotnemu liczeniu nazw plików z nową linią (chociaż używanie wci -print0nie ma większego znaczenia).

Wynik drugiego findjest umieszczany w argumencie echotak, aby nazwa katalogu mogła być łatwo umieszczona w tym samym wierszu ( $(..)konstrukcja automatycznie przycina nowy wiersz na końcu grep). Linie są następnie sortowane według liczby, a 50 największych liczb jest pokazanych za pomocą head.

Zauważ, że obejmie to także katalogi punktów montowania najwyższego poziomu. Prostym sposobem obejścia tego problemu jest użycie podłączenia mount, a następnie skorzystanie z katalogu podłączenia. Aby to zrobić:

sudo mount --bind / /mnt

Bardziej przenośne rozwiązanie korzysta z innej instancji powłoki dla każdego katalogu (również tutaj odpowiedziano ):

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

Przykładowe dane wyjściowe:

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
źródło
11

AKTUALIZACJA: Zrobiłem to wszystko poniżej, co jest fajne, ale wymyśliłem lepszy sposób sortowania katalogów według użycia i-węzła:

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

A jeśli chcesz pozostać w tym samym systemie plików, robisz:

du --inodes -xS

Oto kilka przykładowych danych wyjściowych:

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

TERAZ Z LS:

Kilka osób wspomniało, że nie mają aktualnych coreutils, a opcja --inodes nie jest dla nich dostępna. Oto 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

To zapewnia mi prawie identyczne wyniki z dupoleceniem:

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:

Myślę, że includerzecz zależy tylko od tego, który katalog najpierw program wygląda - ponieważ są to te same pliki i są dowiązane. Trochę jak powyższa rzecz. Mogę się jednak mylić - i z zadowoleniem przyjmuję korektę ...

Podstawową metodą tego jest to, że zastępuję każdą z lsnazw plików zawartymi w niej nazwami katalogów. sed.Po tym ... Cóż, jestem trochę rozmyty. Jestem całkiem pewien, że dokładnie zlicza pliki, jak widać tutaj:

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

Utwórz katalog testowy:

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

Niektóre katalogi dzieci:

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

Zrób kilka plików:

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

Niektóre twarde linki:

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

Spójrz na twarde linki:

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

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

Są liczeni sami, ale idź o jeden katalog wyżej ...

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

Następnie uruchomiłem mój uruchomiony skrypt od dołu i:

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

A Graeme's:

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

Myślę więc, że to pokazuje, że jedynym sposobem zliczania i-węzłów jest użycie i-węzła. A ponieważ zliczanie plików oznacza zliczanie i-węzłów, nie można podwójnie zliczać i-węzłów - aby dokładnie zliczyć pliki, nie można zliczyć więcej niż raz.

STARY:

Znajduję to szybciej i jest przenośny:

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

Nie musi tak być w -execprzypadku każdego katalogu - używa tylko jednego shprocesu ell i jednego find. Muszę nadal mieć set -- $globprawo do dołączania .hiddenplików i wszystkiego innego, ale jest bardzo blisko i bardzo szybko. Wystarczy cdsprawdzić w katalogu głównym, aby sprawdzić i rozpocząć.

Oto przykład mojego wyjścia z /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

Używam również sedu dołu, aby przyciąć go do 50 najlepszych wyników. headbyłoby oczywiście szybsze, ale w razie potrzeby przycinam również każdą linię:

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

Wprawdzie to prymitywne, ale to była myśl. Innym prymitywnym urządzeniem, z którego korzystam, jest zrzutowanie 2>stderrzarówno do, jak findi cddo 2>/dev/null. Jest to po prostu czystsze niż sprawdzanie błędów uprawnień dla katalogów, których nie mogę odczytać bez dostępu do katalogu głównego - być może powinienem to określić find. Cóż, to praca w toku.

Ok, więc naprawiłem globusy powłoki w ten sposób:

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

I faktycznie zamiar zadać pytanie, w jaki sposób można to zrobić, ale jak byłem wpisując w tytule zapytania strona wskazała mnie do sugerowanej powiązane pytanie , gdzie lo i oto już Stephane zważono . To było wygodne. Najwyraźniej [^.],dobrze obsługiwany, nie jest przenośny i musisz użyć !bang.I znalazłem to w komentarzu Stephane'a.

W każdym razie, oczywiście wciągnięcie ukrytych plików nie wystarczyło. Muszę więc setdwa razy, aby uniknąć szukania literału dla pozycji $glob. Wydaje się jednak, że wcale nie wpływa to na wydajność i niezawodnie dodaje każdy plik w katalogu.

mikeserv
źródło
@Graeme Wiesz, żadne z naszych rozwiązań nie obsługuje faktycznie i-węzłów. Wiele z wymienionych przez nas plików jest prawdopodobnie połączonych ze sobą na stałe. Myślę, że mógłbym to zrobić ls -ii ... chyba ... prawdopodobnie grep... może - no cóż, używasz, -xdev,co jest początkiem ... uniqi sort?
mikeserv
Z dujakiej wersji korzystasz ? Mój dunie ma --inodesopcji.
Patrick
@Patrick - może chcę zaktualizować - ale zaktualizowałem post.
mikeserv
To najnowsza funkcja :-) Używam 8.21. Wygląda na to, że został dodany 27.07.2013: git.savannah.gnu.org/gitweb/…
Patrick
Ponadto, jeśli nie masz nic przeciwko, możesz opublikować to pytanie . Nie sądzę, żebym to zaakceptował, ponieważ nie jest zbyt przenośny, ale poprę głos i byłoby miło mieć inne rozwiązanie tego pytania.
Patrick
1

Dlaczego nie użyć czegoś takiego jak KDirStat Chociaż został pierwotnie napisany dla KDE, ale działa również dobrze z GNOME. Daje najlepszy widok liczby plików / katalogów i odpowiedniego wykorzystania w GUI

friendyogi
źródło
1
Poszukuję metody wiersza poleceń.
slm