Finden Sie die Top 50 Verzeichnisse mit den meisten Dateien / Verzeichnissen in der ersten Ebene?

21

Wie kann ich findeine Liste von Verzeichnissen erstellen, die die meisten Dateien enthalten? Ich möchte, dass die Liste von der höchsten zur niedrigsten geht. Ich möchte nur, dass die Auflistung eine Ebene tiefer geht, und ich führe diesen Befehl normalerweise von oben in meinem Dateisystem aus, dh /.

slm
quelle
Unterschiedliche Frage (tatsächlich gleich, aber unterschiedlich gestellt), aber würde die Antwort Ihre Frage nicht auch lösen? unix.stackexchange.com/questions/117093/…
Patrick
Auch in Verbindung stehend - stackoverflow.com/questions/15216370/... . Dies ist, was ich meine ursprüngliche Antwort auf die Inode-Frage von gründete, obwohl ich denke, dass mein Ansatz einige Verbesserungen gegenüber denen dort bietet.
Graeme
@Patrick - Dies ist ein geladenes Q, nur um Graemes A unterzubringen. Richtig, die Bits sind in den anderen Q's A's vergraben, aber dies diente dazu, dieses Bit herauszubringen, damit in Zukunft auf es verwiesen werden kann.
slm
@slm Dann verstehe ich wirklich nicht, warum dies kein Duplikat ist. Seine Antwort scheint nur eine Ausarbeitung einer Antwort auf eine andere Frage zu sein. Jetzt haben wir drei Fragen für dasselbe. Ich denke, die Antwort auf meinem Link ist auch sauberer. Das Starten einer Shell für jedes gefundene Verzeichnis fühlt sich nur schmutzig an.
Patrick
1
@Patrick, ich habe die Antwort überarbeitet, damit die GNU-Lösung nicht für jedes Verzeichnis eine neue Shell startet. Beachten Sie jedoch, dass dies die Standardlösung für den portablen Umgang mit Dateinamen ist.
Graeme

Antworten:

17

Verwenden von GNU-Tools:

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

Dies verwendet zwei findBefehle. Der erste findet Verzeichnisse und leitet sie an eine whileSchleife weiter. Der nächste Suchvorgang wird für jedes Verzeichnis ausgeführt. Die zweite listet alle untergeordneten Dateien / Verzeichnisse auf der ersten Ebene auf, während grepsie gezählt werden. Das greperlaubt -print0, mit dem zweiten Fund verwendet zu werden, da wckein -zÄquivalent vorhanden ist. Dies verhindert, dass Dateinamen mit einer neuen Zeile zweimal gezählt werden (obwohl die Verwendung von wcund no -print0keinen großen Unterschied macht).

Das Ergebnis der Sekunde findwird in das Argument to eingefügt , echosodass der Verzeichnisname problemlos in dieselbe Zeile $(..)eingefügt werden kann (das Konstrukt schneidet die neue Zeile am Ende von automatisch ab grep). Die Zeilen werden dann nach Nummer sortiert und die 50 größten Zahlen mit angezeigt head.

Beachten Sie, dass dies auch die Verzeichnisse der Mount-Punkte der obersten Ebene einschließt. Eine einfache Möglichkeit, dies zu umgehen, besteht darin, ein Bind-Mount zu verwenden und dann das Verzeichnis des Mount zu verwenden. Um dies zu tun:

sudo mount --bind / /mnt

Eine portablere Lösung verwendet für jedes Verzeichnis eine andere Shell-Instanz (auch hier beantwortet ):

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

Beispielausgabe:

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
quelle
11

UPDATE: Ich habe das alles unten gemacht, was cool ist, aber ich habe mir eine bessere Methode ausgedacht, um Verzeichnisse nach Inode-Verwendung zu sortieren:

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

Und wenn Sie im selben Dateisystem bleiben möchten, tun Sie Folgendes:

du --inodes -xS

Hier ist ein Beispiel für eine Ausgabe:

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

JETZT MIT LS:

Einige Personen gaben an, dass sie keine aktuellen coreutils haben und die Option --inodes für sie nicht verfügbar ist. Also, hier ist 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

Dies liefert mir ziemlich identische Ergebnisse wie der duBefehl:

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:

Ich denke, die includeSache hängt nur davon ab, auf welches Verzeichnis das Programm zuerst schaut - weil sie die gleichen Dateien und fest verbunden sind. Irgendwie gefällt mir das Ding oben. Ich könnte mich jedoch irren - und ich begrüße die Korrektur ...

Die zugrunde liegende Methode ist, dass ich jeden lsDateinamen durch den darin enthaltenen Verzeichnisnamen ersetze. sed.Darauf aufbauend ... Nun, ich bin selbst ein bisschen verschwommen. Ich bin mir ziemlich sicher, dass die Dateien genau gezählt werden, wie Sie hier sehen können:

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

Erstellen Sie ein Testverzeichnis:

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

Einige Kinderverzeichnisse:

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

Machen Sie einige Dateien:

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

Einige 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       .

Schauen Sie sich die Hardlinks an:

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

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

Sie werden alleine gezählt, gehen aber ein Verzeichnis hoch ...

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

Dann habe ich mein Skript von unten ausgeführt und:

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

Und Graemes:

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

Ich denke, das zeigt, dass der einzige Weg, Inodes zu zählen, der Inode ist. Und weil das Zählen von Dateien das Zählen von Inodes bedeutet, können Sie Inodes nicht doppelt zählen - um Dateien genau zu zählen, können Inodes nicht mehr als einmal gezählt werden.

ALT:

Ich finde das schneller und es ist portabel:

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

Es muss nicht -execfür jedes Verzeichnis gelten - es werden nur der eine shund der eine Ell-Prozess verwendet find. Ich muss noch das set -- $globRecht bekommen , .hiddenDateien und alles andere einzuschließen, aber es ist sehr nah und sehr schnell. Du würdest einfach cdin was auch immer dein Root-Verzeichnis sein soll für die Prüfung und los geht's.

Hier ist ein Beispiel meiner Ausgabe von /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

Ich benutze dort auch sedam unteren Rand, um es auf die oberen 50 Ergebnisse zu trimmen. headwäre natürlich schneller, aber ich schneide bei Bedarf auch jede Zeile zu:

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

Zugegeben, es ist grob, aber es war ein Gedanke. Ein anderes rohes Gerät, das ich benutze, ist das Dumping 2>stderrfür beide findund cdin 2>/dev/null. Es ist nur sauberer, als sich Berechtigungsfehler für Verzeichnisse anzusehen, die ich ohne Root-Zugriff nicht lesen kann - vielleicht sollte ich das spezifizieren find. Nun, es ist eine laufende Arbeit.

Ok, also habe ich die Shell-Globs folgendermaßen repariert:

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

Eigentlich wollte ich eine Frage stellen, wie es gemacht werden könnte, aber als ich den Fragentitel eintippte, verwies mich die Site auf eine vorgeschlagene verwandte Frage , in die Stephane bereits eingewogen hatte . Das war praktisch. Anscheinend ist es [^.],zwar gut unterstützt, aber nicht tragbar und man muss das benutzen, was !bang.ich in Stephanes Kommentar dort gefunden habe.

Auf jeden Fall war es offensichtlich nicht genug, nur versteckte Dateien einzulesen. Ich muss also setzweimal suchen, um zu vermeiden, dass nach dem Wortlaut gesucht wird $glob. Trotzdem scheint es die Leistung überhaupt nicht zu beeinträchtigen, und es fügt zuverlässig jede Datei im Verzeichnis hinzu.

U / min mikeserv
quelle
@Graeme Sie wissen, dass keine unserer Lösungen tatsächlich Inodes verarbeitet. Viele der von uns aufgelisteten Dateien sind wahrscheinlich fest miteinander verknüpft. Ich denke, ich könnte das tun mit ls -iund ... ich denke ... wahrscheinlich grep... vielleicht - nun, du verwendest -xdev,was ein Anfang ist ... uniqund sort?
mikeserv
Von welcher Version duläufst du? Meiner duhat keine --inodesOption.
Patrick
@Patrick - möchte vielleicht aktualisieren - aber ich habe den Beitrag aktualisiert.
mikeserv
Das ist ein brandaktuelles Feature :-) Ich verwende 8.21. Sieht aus wie es hinzugefügt wurde 2013-07-27: git.savannah.gnu.org/gitweb/…
Patrick
Wenn es Ihnen nichts ausmacht, können Sie das auch zu dieser Frage posten . Ich glaube nicht, dass ich das akzeptieren werde, da es nicht sehr portabel ist, aber ich werde dafür stimmen, und es wäre schön, eine andere Lösung für die Frage zu haben.
Patrick
1

Warum nicht so etwas wie KDirStat verwenden? Obwohl es ursprünglich für KDE geschrieben wurde, aber auch mit GNOME gut funktioniert. Es gibt Ihnen die beste Sicht auf die Anzahl der Dateien / Verzeichnisse und die jeweilige Verwendung in der GUI

friendyogi
quelle
1
Kommandozeilenmethode suchen.
slm