Come posso ordinare l'output du -h per dimensione


967

Ho bisogno di ottenere un elenco di output leggibile dall'uomo.

Tuttavia, dunon ha un'opzione "ordina per dimensione" e il piping su sortnon funziona con la bandiera leggibile dall'uomo.

Ad esempio, eseguendo:

du | sort -n -r 

Emette un utilizzo del disco ordinato per dimensione (decrescente):

du |sort -n -r
65108   .
61508   ./dir3
2056    ./dir4
1032    ./dir1
508     ./dir2

Tuttavia, eseguendolo con la bandiera umana leggibile, non si ordina correttamente:

du -h | sort -n -r

508K    ./dir2
64M     .
61M     ./dir3
2.1M    ./dir4
1.1M    ./dir1

Qualcuno sa un modo per ordinare du -h per dimensione?


Eh ... divertente, dovresti chiedere, dato che questo mi ha infastidito per ... almeno oltre un anno. La scorsa settimana ho scaricato il codice su GNU coreutils (di cui fa parte una specie), e ho dato un'occhiata, ma ho deciso che ci sarebbe voluto un po 'più di tempo di quello che avevo in mano per patchare ... Qualcuno? :)
Rilassati il

Ecco una domanda molto correlata: serverfault.com/q/737537/35034
cregox

Hai visto questo? unix.stackexchange.com/questions/4681/… È quasi un duplicato e vale oro. Fai un normale duma aggiungi -h al sortcomando. Puoi aggiungere in -rhmodo che i più grandi siano i primi nel file, altrimenti devi tailvedere i porci dello spazio.
SDsolar,

Non mi aspettavo che una domanda del genere fosse così popolare quando ho cercato su Google questo.
Mateen Ulhaq,

Risposte:


1363

A partire da GNU coreutils 7.5 rilasciato nell'agosto 2009, sortconsente un -hparametro, che consente suffissi numerici del tipo prodotto da du -h:

du -hs * | sort -h

Se stai usando un ordinamento che non supporta -h, puoi installare GNU Coreutils. Ad esempio su un Mac OS X precedente:

brew install coreutils
du -hs * | gsort -h

Dal sort manuale :

-h, --human-numeric-sort compare human readable numbers (e.g., 2K 1G)


3
La sezione pertinente del manuale: gnu.org/software/coreutils/manual/…
wodow,

29
Facile da installare su OS X con homebrew - brew install coreutils.
Richard Poirier,

41
Buona! Personalmente ho sempre fatto du -BM | sort -nruna soluzione alternativa - è abbastanza leggibile dall'uomo, ed è ordinato, se qualcuno è bloccato con coreutils più vecchi.
Chutz,

30
Se si utilizza su OSX tramite Homebrew, si noti che ora è necessario utilizzare gsort piuttosto che ordinare:du -hs * | gsort -h
Brian Cline,

2
@PaulDraper, du -BMstampa tutto in megabyte, quindi un file di 168 KB verrebbe effettivamente visualizzato come 0M. A meno che non ci sia qualche altra discrepanza di versione di cui non sono a conoscenza. La mia versione dumostra solo valori di megabyte interi.
chutz,

88
du | sort -nr | cut -f2- | xargs du -hs

48
E farà un'enorme quantità di conteggi duplicati.
Douglas Leeder,

1
Prima fa il normale du - poi per ogni voce ricalcola la dimensione solo per stamparla in forma leggibile dall'uomo.
Douglas Leeder,

8
@Douglas Leeder: hai ragione per il conteggio dei duplicati, ma pensi che il secondo du non inizi dalla cold cache (grazie al sistema operativo) @hasen j: xargs è un comando molto utile, divide il suo stdin e lo alimenta come argomenti al comando dato
cadrian,

4
Chris's è in realtà superiore poiché funziona con percorsi contenenti spazi bianchi. Lancia un voto a modo tuo, amico.
rbright,

3
Brutto, ma multipiattaforma :).
voretaq7,

62

@Douglas Leeder, un'altra risposta: ordina l'output leggibile da du -h usando un altro strumento. Come Perl!

du -h | perl -e 'sub h{%h=(K=>10,M=>20,G=>30);($n,$u)=shift=~/([0-9.]+)(\D)/;
return $n*2**$h{$u}}print sort{h($b)<=>h($a)}<>;'

Dividi su due righe per adattarsi al display. Puoi usarlo in questo modo o renderlo un one-liner, funzionerà in entrambi i modi.

Produzione:

4.5M    .
3.7M    ./colors
372K    ./plugin
128K    ./autoload
100K    ./doc
100K    ./syntax

EDIT: dopo alcune partite di golf a PerlMonks , il risultato finale è il seguente:

perl -e'%h=map{/.\s/;99**(ord$&&7)-$`,$_}`du -h`;die@h{sort%h}'

2
La tua versione breve viene emessa a stderrcausa della diepossibilità di cambiarla per renderla attiva stdout?
Dennis Williamson,

2
Cambia diein a printe andrà a stdout. Sono solo altri due personaggi.
Adam Bellaire,

funziona su Ubuntu!
marinara,

impressionante perl hackistry
nandoP

Il risultato è in ordine inverso :(
RSFalcon7

55

Esiste uno strumento immensamente utile che uso, chiamato ncdu, progettato per trovare quei fastidiosi file e cartelle con elevato utilizzo del disco e rimuoverli. È basato su console, veloce e leggero e ha pacchetti su tutte le principali distribuzioni.


Molto bello ... Mi chiedo se i risultati possano essere forniti allo standard ... Sono così pigro che non riesco a leggere il manuale
ojblass

8
gt5 è nella stessa vena; la sua caratteristica killer sta mostrando crescita.
Tobu,

1
È davvero fantastico! E molto più veloce che andare in giro con du, se vuoi solo identificare le grandi directory.
BurninLeo,

44
du -k * | sort -nr | cut -f2 | xargs -d '\n' du -sh

Impossibile utilizzare con du -k --total, restituisce un errore alla finedu: cannot access 'total': No such file or directory
laggingreflex

questa mi piace più ogni altra risposta. come andresti a mostrare solo i primi 50 risultati?
Mau,

1
@Mauro: basta semplicemente reindirizzare il risultato headaggiungendo `| testa -50` alla fine.
Samuel Lelièvre,

21

Per quanto posso vedere, hai tre opzioni:

  1. Modifica duper ordinare prima della visualizzazione.
  2. Modifica sortper supportare le dimensioni umane per l'ordinamento numerico.
  3. Post elabora l'output dall'ordinamento per modificare l'output di base in leggibile.

Potresti anche fare du -ke vivere con taglie in KiB.

Per l'opzione 3 è possibile utilizzare il seguente script:

#!/usr/bin/env python

import sys
import re

sizeRe = re.compile(r"^(\d+)(.*)$")

for line in sys.stdin.readlines():
    mo = sizeRe.match(line)
    if mo:
        size = int(mo.group(1))
        if size < 1024:
            size = str(size)+"K"
        elif size < 1024 ** 2:
            size = str(size/1024)+"M"
        else:
            size = str(size/(1024 ** 2))+"G"

        print "%s%s"%(size,mo.group(2))
    else:
        print line

20

Ho avuto anche quel problema e attualmente sto usando una soluzione alternativa:

du -scBM | sort -n

Ciò non produrrà valori in scala, ma produrrà sempre la dimensione in megabyte. È meno che perfetto, ma per me è meglio di niente (o visualizza la dimensione in byte).


Mi piace l'interruttore -BM, che è fondamentalmente lo stesso di -m, ma ha il vantaggio di visualizzare la dimensione e M postfissati, quindi ottieni 10M che è molto più chiaro di solo 10 :)
Tom Feiner

Questa è la soluzione più semplice che ho visto finora in questa pagina, grazie!
Jeff Olson,

19

Ho trovato questo post altrove. Pertanto, questo script di shell farà ciò che desideri senza richiamare dututto due volte. Usa awkper convertire i byte grezzi in un formato leggibile dall'uomo. Naturalmente, la formattazione è leggermente diversa (tutto viene stampato con una precisione decimale).

#/bin/bash
du -B1 | sort -nr  |awk '{sum=$1;
hum[1024**3]="G";hum[1024**2]="M";hum[1024]="K";
for (x=1024**3; x>=1024; x/=1024){
        if (sum>=x) { printf "%.1f%s\t\t",sum/x,hum[x];print $2;break
}}}'

L'esecuzione di questo nella mia .vimdirectory produce:

4.4M            .
3.6M            ./colors
372.0K          ./plugin
128.0K          ./autoload
100.0K          ./syntax
100.0K          ./doc

(Spero che 3,6 milioni di combinazioni di colori non siano eccessive.)


1
Anch'io ho una risposta al Perl, ma penso che potrebbe far odiare la gente: du -B1 | ordina -nr | perl -e '% h = (0 => b, 1 => K, 2 => M, 3 => G); per (<>) {($ s, @ f) = split / \ s + /; $ e = 3; $ e-- while (1024 ** $ e> $ s); $ v = ($ s / (1024 ** $ e)); printf "% -8s% s \ n", sprintf ($ v> = 100? "% d% s": "% .1f% s", $ s / (1024 ** $ e), $ h {$ e}), @ f;} '
Adam Bellaire,

Anche se la risposta Perl in realtà dà la sua formattazione molto più vicina a du. Anche se l'arrotondamento è disattivato ... Sembra che du dia sempre ceil () piuttosto che round ()
Adam Bellaire,

Ehi, perché ho usato un hash lì? Avrei dovuto essere una schiera ... brontolio del cervello mattutino ....
Adam Bellaire,

Aggiunta una soluzione Perl migliore come altra risposta.
Adam Bellaire,

Entrambe le versioni falliscono quando i nomi dei file contengono spazi
Vi.

15

Questa versione consente awkdi creare colonne aggiuntive per le chiavi di ordinamento. Chiama solo duuna volta. L'output dovrebbe apparire esattamente come du.

L'ho diviso in più righe, ma può essere ricombinato in una riga.

du -h |
  awk '{printf "%s %08.2f\t%s\n", 
    index("KMG", substr($1, length($1))),
    substr($1, 0, length($1)-1), $0}' |
  sort -r | cut -f2,3

Spiegazione:

  • INIZIA - crea una stringa da indicizzare per sostituire 1, 2, 3 con K, M, G per il raggruppamento per unità, se non c'è unità (la dimensione è inferiore a 1K), allora non c'è corrispondenza e viene restituito uno zero (perfetto! )
  • stampa i nuovi campi - unità, valore (per far funzionare correttamente l'ordinamento alfa è a zero, lunghezza fissa) e linea originale
  • indicizza l'ultimo carattere del campo dimensione
  • estrarre la parte numerica della dimensione
  • ordina i risultati, scarta le colonne extra

Provalo senza il cutcomando per vedere cosa sta facendo.

Ecco una versione che esegue l'ordinamento all'interno dello script AWK e non ha bisogno di cut:

du -h |
   awk '{idx = sprintf("%s %08.2f %s", 
         index("KMG", substr($1, length($1))),
         substr($1, 0, length($1)-1), $0);
         lines[idx] = $0}
    END {c = asorti(lines, sorted);
         for (i = c; i >= 1; i--)
           print lines[sorted[i]]}'

grazie! questo è il primo esempio che funziona per me in OS X 10.6 senza contare gli script perl / phython. e grazie ancora per la buona spiegazione. sempre bello imparare qualcosa di nuovo. Awk è sicuramente uno strumento potente.
Lupo,

Grazie mille per quello. Ho cambiato il du per du -sh *mostrare solo i file e le directory immediate senza discesa ricorsiva.
HankCa,

15

Ecco un esempio che mostra le directory in una forma riepilogativa più compatta. Gestisce gli spazi nella directory / nomi dei file.

% du -s * | sort -rn | cut -f2- | xargs -d "\n" du -sh

53G  projects
21G  Desktop
7.2G VirtualBox VMs
3.7G db
3.3G SparkleShare
2.2G Dropbox
272M apps
47M  incoming
14M  bin
5.7M rpmbuild
68K  vimdir.tgz

1
Gli utenti macOS / OSX devono essere avvisati che la versione mac di xargs non supporta il flag -d e, se lo ometti, tutte le directory che contengono uno spazio hanno analizzato ogni parola separatamente, il che ovviamente fallisce.
jasonology,

11

ordina i file per dimensione in MB

du --block-size=MiB --max-depth=1 path | sort -n

9

Ho un wrapper in pitone semplice ma utile per du chiamato dutop . Si noti che noi (i manutentori di coreutils) stiamo valutando di aggiungere la funzionalità di ordinamento per ordinare direttamente l'output "umano".


1
+1 per una delle rare, valide eccezioni a "fare una cosa e farlo bene". A meno che qualcuno non riesca a capire il prefisso SI e / oi prefissi binari.
Joachim Sauer,

E come ptman menziona di seguito: ta da ! (nuova sortbandiera)
Tobu,

9

Ne ho un altro:

$ du -B1 | sort -nr | perl -MNumber::Bytes::Human=format_bytes -F'\t' -lane 'print format_bytes($F[0])."\t".$F[1]'

Sto iniziando ad apprezzare il perl. Potrebbe essere necessario fare un

$ cpan Number::Bytes::Human

primo. A tutti gli hacker di perl là fuori: Sì, so che la parte di ordinamento può essere eseguita anche in perl. Probabilmente anche la seconda parte.


8

Questo frammento è stato sfacciato senza vergogna da "Jean-Pierre" da http://www.unix.com/shell-programming-scripting/32555-du-h-sort.html . C'è un modo in cui posso dargli credito?

du -k | sort -nr | awk '
     BEGIN {
        split("KB,MB,GB,TB", Units, ",");
     }
     {
        u = 1;
        while ($1 >= 1024) {
           $1 = $1 / 1024;
           u += 1
        }
        $1 = sprintf("%.1f %s", $1, Units[u]);
        print $0;
     }
    '

penso che se è un numero molto grande, quindi l'unità è sparita e il numero visualizzato è piccolo ... prova23423423432423
nopole

7

Usa il flag "-g"

 -g, --general-numeric-sort
              compare according to general numerical value

E sulla mia directory / usr / local produce output in questo modo:

$ du |sort -g

0   ./lib/site_ruby/1.8/rubygems/digest
20  ./lib/site_ruby/1.8/rubygems/ext
20  ./share/xml
24  ./lib/perl
24  ./share/sgml
44  ./lib/site_ruby/1.8/rubygems/package
44  ./share/mime
52  ./share/icons/hicolor
56  ./share/icons
112 ./share/perl/5.10.0/YAML
132 ./lib/site_ruby/1.8/rubygems/commands
132 ./share/man/man3
136 ./share/man
156 ./share/perl/5.10.0
160 ./share/perl
488 ./share
560 ./lib/site_ruby/1.8/rubygems
604 ./lib/site_ruby/1.8
608 ./lib/site_ruby

4
Ciò non dà però un risultato leggibile dall'uomo, che è ciò che l'OP stava cercando.

4

Un altro:

du -h | perl -e'
@l{ K, M, G } = ( 1 .. 3 );
print sort {
    ($aa) = $a =~ /(\w)\s+/;
    ($bb) = $b =~ /(\w)\s+/;
    $l{$aa} <=> $l{$bb} || $a <=> $b
  } <>'

4

Ecco il semplice metodo che utilizzo, un utilizzo delle risorse molto basso e ti offre ciò di cui hai bisogno:

du --max-depth=1 | sort -n | awk 'BEGIN {OFMT = "%.0f"} {print $1/1024,"MB", $2}'

0 MB ./etc
1 MB ./mail
2 MB ./tmp
123 MB ./public_html

4

Trovato questo online ... sembra funzionare bene

du -sh * | tee /tmp/duout.txt | grep G | sort -rn ; cat /tmp/duout.txt | grep M | sort -rn ; cat /tmp/duout.txt | grep K | sort -rn ; rm /tmp/duout.txt

Liberamente basato su questo one-liner, ho creato uno script per fornire un output du (1) leggibile dall'uomo. Fare riferimento alla mia risposta, serverfault.com/a/937459/218692 .
Tripp Kinetics,

3

Ieri ho imparato a meravigliare inventando questo esempio. Ci è voluto del tempo, ma è stato molto divertente e ho imparato a usare awk.

Funziona solo du una volta e ha un output molto simile a du -h

du --max-depth=0 -k * | sort -nr | awk '{ if($1>=1024*1024) {size=$1/1024/1024; unit="G"} else if($1>=1024) {size=$1/1024; unit="M"} else {size=$1; unit="K"}; if(size<10) format="%.1f%s"; else format="%.0f%s"; res=sprintf(format,size,unit); printf "%-8s %s\n",res,$2 }'

Mostra numeri inferiori a 10 con un punto decimale.


3

du -cka --max-depth = 1 / var / log | ordina -rn | testa -10 | awk '{print ($ 1) / 1024, "MB", $ 2'}


2

Se è necessario gestire gli spazi, è possibile utilizzare quanto segue

 du -d 1| sort -nr | cut -f2 | sed 's/ /\\ /g' | xargs du -sh

L'istruzione sed aggiuntiva aiuterà ad alleviare i problemi con le cartelle con nomi come Supporto applicazioni


Ho appena provato questo su macOS Sierra. Funziona come previsto. Bello!
jasonology,

1

Ecco:

du -sk /var/log/* | sort -rn | awk '{print $2}' | xargs -ia du -hs "a"

1

http://dev.yorhel.nl/ncdu

comando: ncdu

Navigazione della directory, ordinamento (nome e dimensioni), rappresentazione grafica, lettura umana, ecc ...


1
Ottima utility, ma non installata per impostazione predefinita su qualsiasi sistema operativo di cui sono a conoscenza. Non necessariamente un problema, ma un altro programma da
seguire

1

Un'altra awksoluzione -

du -k ./* | sort -nr | 
awk '
{split("KB,MB,GB",size,",");}
{x = 1;while ($1 >= 1024) 
{$1 = $1 / 1024;x = x + 1} $1 = sprintf("%-4.2f%s", $1, size[x]); print $0;}'


[jaypal~/Desktop/Reference]$ du -k ./* | sort -nr | awk '{split("KB,MB,GB",size,",");}{x = 1;while ($1 >= 1024) {$1 = $1 / 1024;x = x + 1} $1 = sprintf("%-4.2f%s", $1, size[x]); print $0;}'
15.92MB ./Personal
13.82MB ./Personal/Docs
2.35MB ./Work Docs
1.59MB ./Work Docs/Work
1.46MB ./Personal/Raa
584.00KB ./scan 1.pdf
544.00KB ./Personal/Resume
44.00KB ./Membership.xlsx
16.00KB ./Membership Transmittal Template.xlsx

1

Stavo usando la soluzione fornita da @ptman, ma una recente modifica del server l'ha resa non più praticabile. Invece, sto usando il seguente script bash:

#!/bin/bash
# File: duf.sh
# list contents of the current directory by increasing 
#+size in human readable format

# for some, "-d 1" will be "--maxdepth=1"
du -k -d 1 | sort -g | awk '
{
if($1<1024)
    printf("%.0f KB\t%s",$1,$2);
else if($1<1024*1024)
    printf("%.1f MB\t%s",$1/1024,$2);
else
    printf("%.1f GB\t%s",$1/1024/1024,$2);
}'

La du -d 1sintassi BSD è stata supportata da GNU du da quando coreutils 8.6 è stato rilasciato nel 2010 (anche se la sua prima disponibilità Red Hat è stata RHEL 7 nel 2014), quindi non è più necessario --maxdepth=1. L'ho scoperto solo di recente da solo.
Adam Katz,


1

Ci sono molte risposte qui, molte delle quali sono duplicati. Vedo tre tendenze: passare in rassegna un secondo du call, usare un complicato codice shell / awk e usare altre lingue.

Ecco una soluzione conforme a POSIX che utilizza du e awk che dovrebbe funzionare su ogni sistema.

Ho adottato un approccio leggermente diverso, aggiungendo -xper assicurarmi di rimanere sullo stesso filesystem (ho sempre bisogno di questa operazione quando ho poco spazio su disco, quindi perché eliminare le cose che ho montato all'interno di questo albero FS o spostato e symlinked back?) e visualizzazione di unità costanti per facilitare l'analisi visiva. In questo caso, in genere scelgo di non ordinare in modo da poter vedere meglio la struttura gerarchica.

sudo du -x | awk '
  $1 > 2^20 { s=$1; $1=""; printf "%7sG%s\n", sprintf("%.2f",s/2^21), $0 }'

(Poiché si tratta di unità coerenti, si può quindi aggiungere | sort -nse si vuole veramente sorta risultati ndr).

Ciò filtra qualsiasi directory il cui contenuto (cumulativo) non superi i 512 MB e quindi visualizza le dimensioni in gigabyte. Per impostazione predefinita, du utilizza una dimensione di blocco di 512 byte (quindi la condizione di awk di 2 20 blocchi è 512 MB e il suo divisore 2 21 converte le unità in GB - potremmo usare du -kxcon $1 > 512*1024e s/1024^2per essere più leggibili dall'uomo). All'interno della condizione awk, abbiamo impostato sle dimensioni in modo da poterlo rimuovere dalla linea ( $0). Ciò mantiene il delimitatore (che viene compresso in un singolo spazio), quindi il finale %srappresenta uno spazio e quindi il nome della directory aggregata. %7sallinea la %.2fdimensione GB arrotondata (aumenta a %8sse hai> 10 TB).

A differenza della maggior parte delle soluzioni qui, questo supporta correttamente le directory con spazi nei loro nomi (anche se ogni soluzione, compresa questa, gestirà in modo errato i nomi delle directory che contengono le interruzioni di riga).


0

Almeno con i soliti strumenti, questo sarà difficile a causa del formato in cui si trovano i numeri leggibili dall'uomo (nota che l'ordinamento fa un "buon lavoro" qui in quanto ordina i numeri - 508, 64, 61, 2, 2 - esso semplicemente non riesco a ordinare i numeri in virgola mobile con un moltiplicatore aggiuntivo).

Vorrei provarlo al contrario: utilizzare l'output di "du | sort -n -r" e successivamente convertire i numeri in formato leggibile dall'uomo con qualche script o programma.


0

Quello che puoi provare è:

for i in `du -s * | sort -n | cut -f2`
do
  du -h $i;
done

Spero che aiuti.


questo è ciò che fa xargs ;-)
cadrian,

hehe, mi dimentico sempre degli xargs. ;) Alla fine della giornata, qualunque cosa faccia il lavoro, imo.

MacOSX per impostazione predefinita (vale a dire al di fuori della birra fatta in casa) non supporta un corretto xargsquindi questo modulo era necessario. Tuttavia, per i file con spazi all'interno è necessario impostare IFS:IFS=$'\n'
HankCa

0
du | sort -nr | awk '{ cmd = "du -h -d0 "$2"| cut -f1"; cmd | getline human; close(cmd); print human"\t"$2 }'
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.