Trova le prime 50 directory che contengono il maggior numero di file / directory nel loro primo livello?


21

Come posso usare findper generare un elenco di directory che contengono il maggior numero di file. Vorrei che l'elenco fosse dal più alto al più basso. Vorrei solo che la lista arrivasse a 1 livello di profondità, e di solito eseguivo questo comando dalla cima del mio filesystem, cioè /.


Domanda diversa (in realtà la stessa, ma fatta in modo diverso), ma la risposta non risolverebbe anche la tua domanda? unix.stackexchange.com/questions/117093/…
Patrick,

Correlati anche - stackoverflow.com/questions/15216370/… . Questo è ciò su cui ho basato la mia risposta originale sulla domanda dell'inode, anche se penso che il mio approccio offra alcuni miglioramenti rispetto a quelli lì.
Graeme,

@Patrick - questa è una Q caricata solo per ospitare Graemes A. Vero i bit sono sepolti nelle altre A di Q, ma questo doveva far emergere questo bit in modo che potesse essere referenziato in futuro.
slm

@slm Allora non capisco perché questo non è un duplicato. La sua risposta sembra essere solo un'elaborazione di una risposta su un'altra domanda. Quindi ora abbiamo 3 domande per la stessa cosa. Penso che anche la risposta sul mio link sia più pulita. Lanciare una shell per ogni directory trovata sembra semplicemente sporco.
Patrick,

1
@Patrick, ho rielaborato la risposta in modo che la soluzione GNU non avvii una nuova shell per ogni directory. Tuttavia nota che questa è la soluzione standard per gestire qualsiasi nome di file in modo portabile.
Graeme,

Risposte:


17

Usando gli strumenti 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

Questo utilizza due findcomandi. Il primo trova le directory e le reindirizza in un whileciclo esegue la successiva ricerca per ogni directory. Il secondo elenca tutti i file / directory figlio nel primo livello mentre grepli conta. Il greppermette -print0di essere utilizzato con il secondo ritrovamento in quanto wcnon ha un -zequivalente. Ciò interrompe il conteggio dei nomi di file con una nuova riga due volte (anche se l'utilizzo wce non -print0farebbe molta differenza).

Il risultato del secondo findviene inserito nell'argomento e echoquindi il nome della directory può essere facilmente posizionato sulla stessa riga (il $(..)costrutto taglia automaticamente la nuova riga alla fine di grep). Le righe vengono quindi ordinate per numero e i 50 numeri più grandi indicati con head.

Nota che questo includerà anche le directory di livello superiore dei punti di mount. Un modo semplice per aggirare il problema è utilizzare un mount bind e quindi usare la directory del mount. Per farlo:

sudo mount --bind / /mnt

Una soluzione più portatile utilizza un'istanza di shell diversa per ogni directory (anche qui fornita risposta ):

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

Uscita campione:

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

11

AGGIORNAMENTO: Ho fatto tutto ciò di seguito, il che è bello, ma ho trovato un modo migliore di ordinare le directory per uso degli inode:

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

E se vuoi rimanere nello stesso filesystem fai:

du --inodes -xS

Ecco alcuni esempi di output:

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

ORA CON LS:

Diverse persone hanno affermato di non avere coreutils aggiornati e l'opzione --inodes non è disponibile per loro. Quindi, ecco 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

Questo mi sta fornendo risultati praticamente identici al ducomando:

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:

Penso che la includecosa dipenda solo dalla directory in cui il programma guarda prima - perché sono gli stessi file e hardlinked. Piace la cosa sopra. Potrei sbagliarmi però - e accolgo con favore la correzione ...

Il metodo alla base di questo è che sostituisco ognuno dei lsnomi di file con il suo nome di directory contenente in sed.seguito da quello ... Beh, sono un po 'sfocato anch'io. Sono abbastanza certo che sta contando accuratamente i file, come puoi vedere qui:

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

Crea una directory di prova:

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

Alcune directory per bambini:

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

Crea alcuni file:

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

Alcuni hardlink:

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

Guarda i collegamenti:

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

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

Sono contati da soli, ma vanno in alto di una directory ...

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

Quindi ho eseguito il mio script run dal basso e:

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

E Graeme's:

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

Quindi penso che ciò dimostri che l'unico modo per contare gli inode è l'inode. E poiché contare i file significa contare gli inode, non è possibile contare doppiamente gli inode - per contare i file con precisione gli inode non possono essere conteggiati più di una volta.

VECCHIO:

Lo trovo più velocemente ed è portatile:

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

Non è necessario -execper ogni directory: utilizza solo il shprocesso ell e uno find. Devo avere set -- $globancora il diritto di includere i .hiddenfile e tutto il resto, ma è molto vicino e molto veloce. Ti basta cdinserire la directory principale per il controllo e il gioco è fatto.

Ecco un esempio del mio output eseguito da /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

Uso anche sedlì in basso per tagliare i primi 50 risultati. headsarebbe più veloce, ovviamente, ma taglio anche ogni riga se necessario:

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

È rozzo, è vero, ma era un pensiero. Un altro uso Ho dispositivo greggio è dumping 2>stderrper entrambi finde cdin 2>/dev/null. È solo più pulito che guardare gli errori di autorizzazione per le directory che non posso leggere senza accesso root - forse dovrei specificarlo find. Bene, è un work in progress.

Ok, quindi ho corretto i globs della shell in questo modo:

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

In realtà stavo per fare una domanda su come si potesse fare, ma mentre scrivevo il titolo della domanda il sito mi ha indicato una domanda correlata suggerita in cui, ecco, Stephane aveva già ponderato . Quindi era conveniente. Apparentemente [^.],ben supportato, non è portatile e devi usare quello che !bang.ho trovato nel commento di Stephane lì.

Ad ogni modo, semplicemente inserire file nascosti non era abbastanza, ovviamente. Quindi devo fare setdue volte per evitare di cercare i letterali per il letterale $glob. Tuttavia, non sembra influenzare affatto le prestazioni e aggiunge in modo affidabile tutti i file nella directory.


@Graeme Sai, nessuna delle nostre soluzioni gestisce effettivamente gli inode. Molti di quei file che stiamo elencando sono probabilmente collegati l'uno all'altro. Penso che potrei farlo con ls -ie ... suppongo ... probabilmente grep... forse ... beh, stai usando -xdev,quale è un inizio ... uniqe sort?
Mikeserv,

Quale versione di dustai eseguendo? Il mio dunon ha --inodesopzioni.
Patrick,

@Patrick - potrebbe voler aggiornare - ma ho aggiornato il post.
Mikeserv,

Questa è una caratteristica all'avanguardia :-) Sto correndo 8.21. Sembra che sia stato aggiunto il 27/07/2013: git.savannah.gnu.org/gitweb/…
Patrick,

Inoltre, se non ti dispiace, potresti pubblicarlo su questa domanda . Non credo che lo accetterò perché non è molto portatile, ma voterò a fondo e sarebbe bello avere un'altra soluzione sulla domanda.
Patrick,

1

Perché non usare qualcosa come KDirStat Sebbene sia stato originariamente scritto per KDE ma funziona bene anche con GNOME Ti dà la migliore visione del numero di file / dir e del rispettivo utilizzo nella GUI


1
Alla ricerca del metodo da riga di comando.
slm
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.