Como posso classificar du -h de saída por tamanho


967

Preciso obter uma lista de saída duplamente legível por humanos.

No entanto, dunão possui uma opção "classificar por tamanho" e a canalização para sortnão funciona com o sinalizador legível por humanos.

Por exemplo, executando:

du | sort -n -r 

Produz um uso classificado do disco por tamanho (decrescente):

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

No entanto, executá-lo com o sinalizador legível por humanos não classifica corretamente:

du -h | sort -n -r

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

Alguém sabe uma maneira de classificar du -h por tamanho?


Heh ... Engraçado você deve perguntar, já que isso me incomoda ... há mais de um ano, pelo menos. Na semana passada, baixei o código para o GNU coreutils (de que tipo faz parte) e dei uma olhada, mas decidi que levaria um pouco mais de tempo do que eu tinha em minhas mãos para corrigir ... Alguém? :)
descontraia

Aqui está uma pergunta muito relacionada: serverfault.com/q/737537/35034
cregox

Você já viu esse? unix.stackexchange.com/questions/4681/… É quase uma duplicata e vale ouro. Você faz um normal, dumas adiciona -h ao sortcomando. Você pode adicionar -rhpara que os maiores sejam os primeiros no arquivo, caso contrário, você precisará tailver os porcos espaciais.
precisa saber é o seguinte

Eu não esperava que essa pergunta fosse tão popular quando pesquisei isso no Google.
Mateen Ulhaq

Respostas:


1363

A partir do GNU coreutils 7.5 lançado em agosto de 2009, sortpermite um -hparâmetro que permite sufixos numéricos do tipo produzido por du -h:

du -hs * | sort -h

Se você estiver usando uma classificação que não suporta -h, poderá instalar o GNU Coreutils. Por exemplo, em um Mac OS X mais antigo:

brew install coreutils
du -hs * | gsort -h

Desde sort o manual :

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


3
A seção relevante do manual: gnu.org/software/coreutils/manual/…
wodow em 9/02/11

29
Fácil de instalar no OS X com homebrew - brew install coreutils.
Richard Poirier

41
Um bom! Pessoalmente, sempre fiz isso du -BM | sort -nrcomo uma solução alternativa - é legível por seres humanos o suficiente e é classificada, se alguém estiver preso com coreutils mais antigos.
Chutz

30
Se estiver usando o OSX via Homebrew, observe que agora você precisará usar o gsort em vez de classificar:du -hs * | gsort -h
Brian Cline

2
@PaulDraper, du -BMimprime tudo em megabytes, para que um arquivo de 168K seja exibido como 0M. A menos que haja alguma outra discrepância de versão que eu não conheça. Minha versão dumostra apenas valores inteiros de megabytes.
Chutz

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

48
E fará uma enorme quantidade de contagem duplicada.
25411 Douglas Leeder

1
Primeiro, ele faz o du normal - depois, para cada entrada, recalcula o tamanho apenas para imprimi-lo na forma legível por humanos.
Douglas Leeder

8
@ Douglas Leeder: você está certo para a contagem duplicada, mas acha que o segundo du não inicia a partir do cache frio (graças ao sistema operacional) @hasen j: xargs é um comando muito útil, divide seu stdin e o alimenta como argumentos ao comando dado #
cadrian

4
Chris é realmente superior, pois trabalha com caminhos que contêm espaços em branco. Jogando um voto do seu jeito, amigo.
rbright

3
Feio, mas multiplataforma :).
voretaq7

62

@Douglas Leeder, mais uma resposta: classifique a saída legível por humanos de du -h usando outra ferramenta. Como 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)}<>;'

Divida em duas linhas para caber na tela. Você pode usá-lo dessa maneira ou torná-lo único, pois funcionará de qualquer maneira.

Resultado:

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

EDIT: Após algumas voltas de golfe no PerlMonks , o resultado final é o seguinte:

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

2
Sua versão curta é ativada por stderrcausa da diealteração, para que seja ativada stdout?
Dennis Williamson

2
Altere diepara a printe ele irá para stdout. São apenas mais dois personagens.
23411 Adam Bellaire

funciona no ubuntu!
Marinara

impressionante perl hackistry
nandoP

O resultado está na ordem inversa :(
RSFalcon7

55

Existe uma ferramenta imensamente útil que eu uso chamada ncdu, projetada para encontrar essas pastas e arquivos de alto uso em disco e removê-los. É baseado em console, rápido e leve, e possui pacotes em todas as principais distribuições.


Muito bom ... Eu wondier se os resultados poderiam ser alimentadas com o padrão ... Eu sou tão preguiçoso que eu não posso ler o manual
ojblass

8
GT5 está na mesma linha; seu recurso matador está exibindo crescimento.
Tobu

1
Isso é muito legal! E muito mais rápido do que ficar por aqui du, se você quiser apenas identificar os diretórios grandes.
BurninLeo

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

Não pode usar com du -k --total, dá erro no finaldu: cannot access 'total': No such file or directory
laggingreflex

Eu gosto mais desta outra resposta. como você mostraria apenas os 50 primeiros resultados?
Mau

1
@Mauro - apenas canalize o resultado headadicionando `| cabeça -50` no final.
Samuel Lelièvre

21

Tanto quanto eu posso ver, você tem três opções:

  1. Altere dupara classificar antes da exibição.
  2. Altere sortpara suportar tamanhos humanos para classificação numérica.
  3. Pós-processamento da saída de classificação para alterar a saída básica para legível por humanos.

Você também pode fazer du -ke viver com tamanhos no KiB.

Para a opção 3, você pode usar o seguinte 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

Eu também tive esse problema e atualmente estou usando uma solução alternativa:

du -scBM | sort -n

Isso não produzirá valores escalados, mas sempre produzirá o tamanho em megabytes. Isso é menos que perfeito, mas para mim é melhor que nada (ou exibir o tamanho em bytes).


Eu gosto do switch -BM, que é basicamente o mesmo que -m, mas ele tem a vantagem de exibir o tamanho e o M postfixado, para que você obtenha 10M, que é muito mais claro do que apenas 10 :)
Tom Feiner

Esta é a solução mais simples que já vi até agora nesta página, obrigado!
Jeff Olson

19

Encontrou esta postagem em outro lugar. Portanto, esse script de shell fará o que você deseja, sem precisar chamar dutudo duas vezes. Ele usa awkpara converter os bytes brutos em um formato legível por humanos. Obviamente, a formatação é um pouco diferente (tudo é impresso com precisão de uma casa decimal).

#/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
}}}'

Executar isso no meu .vimdiretório gera:

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

(Espero que 3,6 milhões de esquemas de cores não sejam excessivos.)


1
Também tenho uma resposta Perl, mas acho que isso pode fazer as pessoas me odiarem: du -B1 | ordenar -nr | Perl -e '% h = (0 => b, 1 => K, 2 => M, 3 => G); para (<>) {($ s, @ f) = divisão / \ 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

Mesmo que a resposta Perl realmente dê sua formatação muito mais próxima do du. Embora o arredondamento está fora ... Parece du sempre dá ceil () em vez de round ()
Adam Bellaire

Ei, por que eu usei um hash lá? Deveria ter sido um array ... manhã do cérebro resmungar ....
Adam Bellaire

Adicionada uma solução Perl melhor como outra resposta.
23611 Adam Bellaire

Ambas as versões falham quando os nomes de arquivos contêm espaços
Vi.

15

Esta versão usa awkpara criar colunas extras para chaves de classificação. Só liga duuma vez. A saída deve ser exatamente igual du.

Dividi-o em várias linhas, mas ele pode ser recombinado em uma única linha.

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

Explicação:

  • BEGIN - crie uma string para indexar para substituir 1, 2, 3 por K, M, G por agrupamento por unidades, se não houver nenhuma unidade (o tamanho é menor que 1K), não haverá correspondência e um zero será retornado (perfeito! )
  • imprima os novos campos - unidade, valor (para fazer a classificação alfa funcionar corretamente, é preenchido com zero, comprimento fixo) e linha original
  • indexar o último caractere do campo tamanho
  • retire a parte numérica do tamanho
  • classifique os resultados, descarte as colunas extras

Experimente sem o cutcomando para ver o que está fazendo.

Aqui está uma versão que faz a classificação no script AWK e não precisa 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]]}'

obrigado! este é o primeiro exemplo que funciona para mim no OS X 10.6 sem contar os scripts perl / phython. e obrigado novamente pela boa explicação. sempre bom aprender algo novo. awk com certeza é uma ferramenta poderosa.
Lobo

Muito obrigado por isso. Mudei o du para du -sh *mostrar apenas os arquivos e diretórios imediatos sem descida recursiva.
21716 HankCa

15

Aqui está um exemplo que mostra os diretórios em um formato resumido mais compacto. Ele lida com espaços no diretório / nomes de arquivos.

% 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
Os usuários do macOS / OSX são avisados ​​de que a versão mac do xargs não suporta o sinalizador -d e, se você o omitir, qualquer diretório que contenha um espaço terá cada palavra analisada separadamente, o que obviamente falha.
Jasonology

11

classificar arquivos por tamanho em MB

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

9

Eu tenho um wrapper python simples, mas útil para du chamado dutop . Observe que nós (os mantenedores do coreutils) estamos considerando adicionar a funcionalidade para classificar para classificar diretamente a saída "humana".


1
+1 em uma das raras exceções válidas para "fazer uma coisa e fazer o que é certo". A menos que alguém consiga entender o prefixo SI e / ou os prefixos binários.
Joachim Sauer

E como o ptman menciona abaixo: ta da ! (new sortflag)
Tobu

9

Tenho outro:

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

Estou começando a gostar de perl. Você pode ter que fazer uma

$ cpan Number::Bytes::Human

primeiro. Para todos os hackers perl por aí: Sim, eu sei que a parte de classificação também pode ser feita em perl. Provavelmente também a parte dupla.


8

Esse trecho foi descaradamente descarado de 'Jean-Pierre' em http://www.unix.com/shell-programming-scripting/32555-du-h-sort.html . Existe uma maneira de melhor creditar ele?

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;
     }
    '

eu acho que se é um número muito grande, então a unidade se foi e o número apresentado é pequeno ... tentar23423423432423
nopole

7

Use o sinalizador "-g"

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

E no meu diretório / usr / local produz resultados como este:

$ 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
Isso não fornece uma saída legível para humanos, que é o que o OP estava procurando.

4

Outro:

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

Aqui está o método simples que eu uso, uso muito baixo de recursos e fornece o que você precisa:

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

Encontrei este on-line ... parece funcionar OK

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

Basicamente, com base nessa linha única, criei um script para fornecer uma saída du (1) classificada como legível por humanos. Consulte a minha resposta, serverfault.com/a/937459/218692 .
Tripp Kinetics

3

Aprendi awk ao inventar este exemplo ontem. Demorou algum tempo, mas foi muito divertido e aprendi a usar o awk.

Ele roda apenas du uma vez e tem uma saída muito semelhante à 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 números abaixo de 10 com um ponto decimal.


3

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


2

Se você precisar manipular espaços, poderá usar o seguinte

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

A instrução sed adicional ajudará a aliviar problemas com pastas com nomes como Suporte a aplicativos


Apenas tentei isso no macOS Sierra. Funciona como esperado. Agradável!
Jasonology

1

Voilà:

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

1

http://dev.yorhel.nl/ncdu

command: ncdu

Navegação no diretório, classificação (nome e tamanho), gráficos, legível por humanos, etc ...


1
Ótimo utilitário, mas não instalado por padrão em qualquer sistema operacional que eu conheça. Não necessariamente um problema, mas mais um programa para ter de cuidar ...
voretaq7

1

Outra awksolução -

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

Eu estava usando a solução fornecida pelo @ptman, mas uma alteração recente no servidor deixou de ser viável. Em vez disso, estou usando o seguinte 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);
}'

A du -d 1sintaxe do BSD é suportada pelo GNU du desde que o coreutils 8.6 foi lançado em 2010 (embora sua primeira disponibilidade do Red Hat fosse o RHEL 7 em 2014), então você não precisa mais --maxdepth=1. Eu só descobri isso recentemente.
Adam Katz

1

du -s * | ordenar -nr | corte -f2 | xargs du -sh


Essa não é uma ótima solução, pois percorre o sistema de arquivos duas vezes.
Paul Gear

1

Há muitas respostas aqui, muitas das quais são duplicadas. Vejo três tendências: passando por uma segunda ligação, usando código complicado de shell / awk e usando outros idiomas.

Aqui está uma solução compatível com POSIX usando du e awk que deve funcionar em todos os sistemas.

Adotei uma abordagem um pouco diferente, acrescentando -xpara garantir que permaneçamos no mesmo sistema de arquivos (eu só preciso dessa operação quando tenho pouco espaço em disco, então por que eliminar as coisas que montei nessa árvore do FS ou movi e symlinked back?) e exibindo unidades constantes para facilitar a análise visual. Nesse caso, normalmente escolho não classificar para poder ver melhor a estrutura hierárquica.

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

(Como isso está em unidades consistentes, você poderá anexá- | sort -nlo se realmente quiser classificar os resultados.)

Isso filtra qualquer diretório cujo conteúdo (cumulativo) não exceda 512 MB e exibe tamanhos em gigabytes. Por padrão, du usa um tamanho de bloco de 512 bytes (a condição de 2 20 blocos do awk é de 512 MB e seu divisor 2 21 converte as unidades em GB - poderíamos usar du -kxcom $1 > 512*1024e s/1024^2ser mais legível por humanos). Dentro da condição awk, definimos so tamanho para removê-lo da linha ( $0). Isso mantém o delimitador (que é recolhido em um único espaço); portanto, o final %srepresenta um espaço e, em seguida, o nome do diretório agregado. %7salinha o %.2ftamanho arredondado de GB (aumente para %8sse você tiver> 10 TB).

Diferentemente da maioria das soluções aqui, isso suporta diretórios com espaços em seus nomes (embora todas as soluções, incluindo esta, manuseiem incorretamente os nomes de diretórios que contêm quebras de linha).


0

Pelo menos com as ferramentas usuais, isso será difícil devido ao formato em que os números legíveis por humanos estão (observe que esse tipo faz um "bom trabalho" aqui, pois classifica os números - 508, 64, 61, 2, 2 - simplesmente não é possível classificar números de ponto flutuante com um multiplicador adicional).

Eu tentaria o contrário - use a saída de "du | sort -n -r" e depois converta os números em formato legível por humanos com algum script ou programa.


0

O que você pode tentar é:

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

Espero que ajude.


isso é o que xargs faz ;-)
cadrian

hehe, eu sempre esqueço xargs. ;) No final do dia, o que quer que seja feito no trabalho.

O MacOSX, por padrão (ou seja, fora da fermentação doméstica) não suporta um apropriado, xargsportanto esse formulário era necessário. No entanto, para arquivos com espaços neles, você precisa definir o 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 }'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.