¿Cómo puedo ordenar la salida du -h por tamaño?

967

Necesito obtener una lista de lectura humana de salida.

Sin embargo, duno tiene una opción de "ordenar por tamaño", y la tubería sortno funciona con la bandera legible por humanos.

Por ejemplo, ejecutando:

du | sort -n -r 

Emite un uso de disco ordenado por tamaño (descendente):

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

Sin embargo, ejecutarlo con el indicador legible por humanos no se ordena correctamente:

du -h | sort -n -r

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

¿Alguien sabe de una manera de ordenar du -h por tamaño?

Tom Feiner
fuente
Je ... Es curioso que preguntes, ya que esto me ha estado molestando durante ... al menos más de un año. La semana pasada descargué el código en GNU coreutils (de los cuales forma parte), y eché un vistazo, pero decidí que tomaría un poco más de tiempo de lo que tenía en mis manos parchear ... ¿Alguien? :)
relajarse
Aquí hay una pregunta muy relacionada: serverfault.com/q/737537/35034
cregox
¿Has visto este? unix.stackexchange.com/questions/4681/… Es casi un duplicado y vale oro. Haces un normal dupero agregas -h al sortcomando. Puede agregar -rhpara que los más grandes estén primero en el archivo; de lo contrario, debe tailver los cerdos espaciales.
SDsolar
No esperaba que tal pregunta fuera tan popular cuando busqué en Google.
Mateen Ulhaq

Respuestas:

1363

A partir de GNU coreutils 7.5 lanzado en agosto de 2009, sortpermite un -hparámetro, que permite sufijos numéricos del tipo producido por du -h:

du -hs * | sort -h

Si está utilizando un tipo que no es compatible -h, puede instalar GNU Coreutils. Por ejemplo, en una Mac OS X anterior:

brew install coreutils
du -hs * | gsort -h

Del sort manual :

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

ptman
fuente
3
La sección relevante del manual: gnu.org/software/coreutils/manual/…
wodow
29
Fácil de instalar en OS X con homebrew - brew install coreutils.
Richard Poirier
41
Bueno uno! Personalmente, siempre lo hice du -BM | sort -nrcomo una solución alternativa: es lo suficientemente legible para los humanos, y está ordenado, si alguien está atrapado con los coreutils más antiguos.
chutz
30
Si usa OSX a través de Homebrew, tenga en cuenta que ahora necesitará usar gsort en lugar de ordenar:du -hs * | gsort -h
Brian Cline
2
@PaulDraper, du -BMimprime todo en megabytes, por lo que un archivo de 168K en realidad se mostrará como 0M. A menos que haya alguna otra discrepancia de versión que desconozco. Mi versión de dusolo muestra valores enteros de megabytes.
chutz 01 de
88
du | sort -nr | cut -f2- | xargs du -hs
cadrian
fuente
48
Y hará una gran cantidad de conteo duplicado.
Douglas Leeder
1
Primero hace el du normal, luego para cada entrada recalcula el tamaño solo para imprimirlo en forma legible para humanos.
Douglas Leeder
8
@ Douglas Leeder: tienes razón para el conteo duplicado, pero piensas que el segundo du no comienza desde el caché en frío (gracias al sistema operativo) @hasen j: xargs es un comando muy útil, divide su stdin y lo alimenta como argumentos al comando dado
cadrian
44
Chris's es realmente superior ya que funciona con rutas que contienen espacios en blanco. Dando un voto a tu manera, amigo.
rbright
3
Feo, pero multiplataforma :).
voretaq7
62

@ Douglas Leeder, una respuesta más: clasifique la salida legible por humanos de du -h usando otra herramienta. ¡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)}<>;'

Dividir en dos líneas para adaptarse a la pantalla. Puede usarlo de esta manera o hacerlo de una sola línea, funcionará de cualquier manera.

Salida:

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

EDITAR: Después de algunas rondas de golf en PerlMonks , el resultado final es el siguiente:

perl -e'%h=map{/.\s/;99**(ord$&&7)-$`,$_}`du -h`;die@h{sort%h}'
Adam Bellaire
fuente
2
Su versión corta se activa stderrdebido a que die¿puede cambiarla para activarla stdout?
Dennis Williamson
2
Cambie el diea printay se irá a stdout. Son solo dos personajes más.
Adam Bellaire
funciona en ubuntu!
marinara
impresionante perl hackistry
nandoP
El resultado es en orden inverso :(
RSFalcon7
55

Hay una herramienta inmensamente útil que uso llamada ncdu que está diseñada para encontrar esas molestas carpetas y archivos de alto uso de disco, y eliminarlos. Está basado en consola, es rápido y ligero, y tiene paquetes en todas las distribuciones principales.


fuente
Muy bonito ... Me wondier si los resultados podrían ser alimentados a la salida estándar ... soy tan perezoso que no puedo leer el manual
ojblass
8
gt5 está en la misma línea; su característica asesina es mostrar crecimiento.
Tobu
1
¡Eso es realmente genial! Y mucho más rápido que pasar el rato du, si solo desea identificar los directorios grandes.
BurninLeo
44
du -k * | sort -nr | cut -f2 | xargs -d '\n' du -sh
Jake Wilson
fuente
No se puede usar con du -k --total, da un error al finaldu: cannot access 'total': No such file or directory
laggingreflex
Me gusta esta otra respuesta. ¿Cómo irías a mostrar solo los primeros 50 resultados?
Mau
1
@Mauro: simplemente canalice el resultado headagregando `| cabeza -50` al final.
Samuel Lelièvre
21

Por lo que puedo ver, tienes tres opciones:

  1. Alterar dupara ordenar antes de mostrar.
  2. Alterar sortpara admitir tamaños humanos para la ordenación numérica.
  3. Postprocese la salida de sort para cambiar la salida básica a legible para humanos.

También puedes hacer du -ky vivir con tamaños en KiB.

Para la opción 3, puede usar el siguiente 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
Douglas Leeder
fuente
20

También tuve ese problema y actualmente estoy usando una solución alternativa:

du -scBM | sort -n

Esto no producirá valores escalados, pero siempre producirá el tamaño en megabytes. Eso es menos que perfecto, pero para mí es mejor que nada (o mostrar el tamaño en bytes).

Joachim Sauer
fuente
Me gusta el interruptor -BM, que es básicamente el mismo que -m, pero tiene la ventaja de mostrar el tamaño y la M fijada, por lo que obtienes 10M, que es mucho más claro que solo 10 :)
Tom Feiner
Esta es la solución más simple que he visto hasta ahora en esta página, ¡gracias!
Jeff Olson
19

Encontré esta publicación en otro lugar. Por lo tanto, este script de shell hará lo que desee sin invocar dutodo dos veces. Se utiliza awkpara convertir los bytes sin formato a un formato legible para humanos. Por supuesto, el formato es ligeramente diferente (todo se imprime con una precisión de un 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
}}}'

Ejecutar esto en mi .vimdirectorio produce:

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

(Espero que 3.6 millones de esquemas de color no sean excesivos).

Adam Bellaire
fuente
1
También tengo una respuesta de Perl, pero creo que podría hacer que la gente me odie: du -B1 | sort -nr | perl -e '% h = (0 => b, 1 => K, 2 => M, 3 => G); para (<>) {($ 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
A pesar de que la respuesta de Perl realmente da su formato mucho más cercano a du. Aunque el redondeo está apagado ... Parece que du siempre da ceil () en lugar de round ()
Adam Bellaire
Oye, ¿por qué usé un hash allí? Debería haber sido una serie ... mañana del cerebro quejarse ....
Adam Bellaire
Se agregó una mejor solución Perl como otra respuesta.
Adam Bellaire
Ambas versiones fallan cuando los nombres de archivo contienen espacios
Vi.
15

Esta versión utiliza awkpara crear columnas adicionales para ordenar las claves. Solo llama duuna vez. La salida debería verse exactamente igual du.

Lo he dividido en varias líneas, pero puede recombinarse en una sola línea.

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

Explicación:

  • COMIENCE - cree una cadena para indexar para sustituir 1, 2, 3 por K, M, G para agrupar por unidades, si no hay unidad (el tamaño es menor a 1K), entonces no hay coincidencia y se devuelve un cero (¡perfecto! )
  • imprima los nuevos campos: unidad, valor (para que la ordenación alfa funcione correctamente es de relleno fijo, longitud fija) y la línea original
  • indexar el último carácter del campo de tamaño
  • sacar la porción numérica del tamaño
  • ordenar los resultados, descartar las columnas adicionales

Pruébelo sin el cutcomando para ver qué está haciendo.

Aquí hay una versión que ordena dentro del script AWK y no necesita 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]]}'
Dennis Williamson
fuente
¡gracias! Este es el primer ejemplo que funciona para mí en OS X 10.6 sin contar los scripts perl / phython. y gracias de nuevo por la buena explicación. Siempre es bueno aprender algo nuevo. awk seguro es una herramienta poderosa.
Wolf
Muchas gracias por eso. Cambié el du para du -sh *mostrar solo los archivos y directorios inmediatos sin descendencia recursiva.
HankCa
15

Aquí hay un ejemplo que muestra los directorios en una forma resumida más compacta. Maneja espacios en el directorio / nombres de archivo.

% 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
slm
fuente
1
Se advierte a los usuarios de macOS / OSX que la versión mac de xargs no es compatible con el indicador -d, y si lo omite, cualquier directorio que contenga un espacio tiene cada palabra analizada por separado, lo que por supuesto falla.
jasonology
11

ordenar archivos por tamaño en MB

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

Tengo un contenedor de python simple pero útil para du llamado dutop . Tenga en cuenta que nosotros (los mantenedores de coreutils) estamos considerando agregar la funcionalidad de ordenar para ordenar la salida "humana" directamente.

pixelbeat
fuente
1
+1 para una de las raras excepciones válidas para "hacer una cosa y hacerlo bien". A menos que alguien se ordene para comprender el prefijo SI y / o los prefijos binarios.
Joachim Sauer
Y como ptman menciona a continuación: ta da ! (nueva sortbandera)
Tobu
9

Tengo otro:

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

Me empieza a gustar Perl. Puede que tengas que hacer un

$ cpan Number::Bytes::Human

primero. Para todos los hackers de Perl: Sí, sé que la parte de clasificación también se puede hacer en Perl. Probablemente la parte du, también.

0x89
fuente
8

Este fragmento fue desvergonzado enganchado de 'Jean-Pierre' de http://www.unix.com/shell-programming-scripting/32555-du-h-sort.html . ¿Hay alguna manera de que pueda acreditarlo mejor?

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;
     }
    '
Bozojoe
fuente
Creo que si es un número muy grande, entonces la unidad se ha ido y el número que se muestra es pequeño ... intente23423423432423
nopole
7

Use la bandera "-g"

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

Y en mi directorio / usr / local produce 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
Mick T
fuente
44
Sin embargo, eso no da la salida legible para humanos, que es lo que estaba buscando el OP.
4

Otro:

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
  } <>'
Dimitre Radoulov
fuente
4

Aquí está el método simple que uso, uso de recursos muy bajo y le brinda lo que necesita:

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
JacobN
fuente
4

Encontré este en línea ... parece funcionar bien

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
Peter NUnn
fuente
Basándome libremente en esta línea, creé un script para proporcionar una salida du (1) ordenada y legible por humanos. Consulte mi respuesta, serverfault.com/a/937459/218692 .
Tripp Kinetics
3

Aprendí awk al inventar este ejemplo ayer. Me llevó algo de tiempo, pero fue muy divertido, y aprendí a usar awk.

Se ejecuta solo du una vez, y tiene una salida muy similar 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 }'

Muestra números por debajo de 10 con un punto decimal.

marlar
fuente
3

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

Patricio
fuente
2

Si necesita manejar espacios, puede usar lo siguiente

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

La declaración adicional de sed ayudará a aliviar problemas con carpetas con nombres como Application Support

Chealion
fuente
Acabo de probar esto en macOS Sierra. Funciona como se esperaba. ¡Agradable!
jasonology
1

Voilà:

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

http://dev.yorhel.nl/ncdu

comando: ncdu

Navegación de directorios, clasificación (nombre y tamaño), gráficos, legibles por humanos, etc.

Adam Eickhoff
fuente
1
Gran utilidad, pero no está instalada por defecto en ningún sistema operativo que conozca No necesariamente es un problema, pero hay que cuidar un programa más ...
voretaq7
1

Otra awksolución

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
usuario96753
fuente
1

Había estado usando la solución proporcionada por @ptman, pero un cambio reciente en el servidor hizo que ya no fuera viable. En cambio, estoy usando el siguiente 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);
}'
Keith Yoder
fuente
La du -d 1sintaxis de BSD ha sido respaldada por GNU du desde que coreutils 8.6 se lanzó en 2010 (aunque su primera disponibilidad de Red Hat fue RHEL 7 en 2014), por lo que ya no la necesita --maxdepth=1. Solo me enteré de esto recientemente.
Adam Katz
1

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

ageek2remember
fuente
Esa no es una gran solución, ya que atraviesa el sistema de archivos dos veces.
Paul Gear
1

Aquí hay muchas respuestas, muchas de las cuales son duplicadas. Veo tres tendencias: pasar por una segunda llamada du, usar código shell / awk complicado y usar otros idiomas.

Aquí hay una solución compatible con POSIX que utiliza du y awk que debería funcionar en todos los sistemas.

He adoptado un enfoque ligeramente diferente, agregando -xpara garantizar que permanezcamos en el mismo sistema de archivos (solo necesito esta operación cuando tengo poco espacio en disco, entonces, ¿por qué eliminar cosas que he montado dentro de este árbol FS o movido y enlace simbólico?) y muestra unidades constantes para facilitar el análisis visual. En este caso, normalmente elijo no ordenar para poder ver mejor la estructura jerárquica.

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

(Dado que esto está en unidades consistentes, puede agregar | sort -nsi realmente desea ordenar los resultados).

Esto filtra cualquier directorio cuyo contenido (acumulativo) no supere los 512 MB y luego muestre los tamaños en gigabytes. Por defecto, du usa un tamaño de bloque de 512 bytes (por lo que la condición de awk de 2 20 bloques es de 512 MB y su divisor de 2 21 convierte las unidades a GB; podríamos usar du -kxcon $1 > 512*1024y s/1024^2para que sea más legible para los humanos). Dentro de la condición awk, establecemos sel tamaño para que podamos eliminarlo de la línea ( $0). Esto retiene el delimitador (que se contrae en un solo espacio), por lo que el final %srepresenta un espacio y luego el nombre del directorio agregado. %7salinea el %.2ftamaño de GB redondeado (aumente a %8ssi tiene> 10 TB).

A diferencia de la mayoría de las soluciones aquí, esto admite correctamente directorios con espacios en sus nombres (aunque cada solución, incluida esta, manejará mal los nombres de directorio que contienen saltos de línea).

Adam Katz
fuente
0

Al menos con las herramientas habituales, esto será difícil debido al formato en el que se encuentran los números legibles por humanos (tenga en cuenta que la clasificación hace un "buen trabajo" aquí, ya que clasifica los números: 508, 64, 61, 2, 2) simplemente no puede ordenar los números de coma flotante con un multiplicador adicional).

Lo intentaría al revés: use la salida de "du | sort -n -r" y luego convierta los números a formato legible para humanos con algún script o programa.

Schnaader
fuente
0

Lo que puedes probar es:

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

Espero que ayude.

Christian Witts
fuente
eso es lo que lo hace ;-) xargs
cadrian
jeje, siempre me olvido de los xargs. ;) Al final del día, cualquier cosa que haga el trabajo de la OMI.
MacOSX de forma predeterminada (es decir, fuera de home-brew) no es compatible con una forma adecuada, xargspor lo que este formulario era necesario. Sin embargo, para los archivos con espacios en ellos, debe configurar 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 }'
Nathan de Vries
fuente