Comment puis-je trier la sortie du -h par taille

968

J'ai besoin d'une liste de résultats lisibles par l'homme.

Cependant, l' duoption "trier par taille" sortn'est pas disponible et la tuyauterie to ne fonctionne pas avec l'indicateur lisible par l'homme.

Par exemple, en cours d'exécution:

du | sort -n -r 

Produit une utilisation du disque trié par taille (décroissant):

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

Cependant, l’exécuter avec le drapeau lisible par l’homme ne trie pas correctement:

du -h | sort -n -r

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

Est-ce que quelqu'un connaît un moyen de trier du -h par taille?

Tom Feiner
la source
Heh ... C'est drôle, demandez-vous, car cela m'agace depuis ... bien au moins un an. La semaine dernière, j'ai téléchargé le code dans GNU Coreutils (dont une partie fait partie) et j’ai jeté un coup d’œil, mais j’ai décidé que cela prendrait un peu plus de temps que de laisser le temps de patcher ... Quelqu'un? :)
décompresser
Voici une question très liée: serverfault.com/q/737537/35034
cregox
As-tu vu celui-là? unix.stackexchange.com/questions/4681/… C'est une copie presque identique et vaut de l'or. Vous faites une opération normale dumais ajoutez le -h à la sortcommande. Vous pouvez ajouter -rhles plus gros en premier dans le fichier, sinon, vous devez tailvoir l'espace.
SDsolar
Je ne m'attendais pas à ce qu'une telle question soit si populaire quand je l'ai cherché dans Google.
Mateen Ulhaq

Réponses:

1364

Depuis GNU, coreutils 7.5, publié en août 2009, sortautorise un -hparamètre permettant des suffixes numériques du type produit par du -h:

du -hs * | sort -h

Si vous utilisez un type qui ne prend pas en charge -h, vous pouvez installer GNU Coreutils. Par exemple, sur un Mac OS X plus ancien:

brew install coreutils
du -hs * | gsort -h

De sort manuel :

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

ptman
la source
3
La section correspondante du manuel: gnu.org/software/coreutils/manual/…
wodow
29
Facile à installer sur OS X avec homebrew - brasser, installez coreutils.
Richard Poirier
41
Bon un! Personnellement, j’ai toujours fait du -BM | sort -nrcomme solution de contournement - c’est assez lisible par l’homme et il est trié, si quelqu'un est coincé avec des coreutils plus anciens.
Chutz
30
Si vous utilisez OSX via Homebrew, notez que vous devrez maintenant utiliser gsort plutôt que de trier:du -hs * | gsort -h
Brian Cline
2
@PaulDraper, affiche du -BMtout en mégaoctets, de sorte qu'un fichier de 168 Ko s'affiche en réalité sous la forme 0M. À moins qu'il y ait un autre écart de version que je ne sache pas. Ma version de dun'affiche que les valeurs en mégaoctets.
Chutz
88
du | sort -nr | cut -f2- | xargs du -hs
cadrien
la source
48
Et ça va faire une énorme quantité de doublons.
Douglas Leeder
1
D’abord, il fait la commande normale - puis, pour chaque entrée, il recalcule la taille pour l’imprimer sous une forme lisible par l’homme.
Douglas Leeder
8
@ Douglas Leeder: vous avez raison pour le comptage des doublons, mais pensez que le second du ne commence pas à partir du cache froid (grâce à l'OS) @hasen j: xargs est une commande très utile, il divise son stdin et le nourrit sous forme d'arguments à la commande donnée
cadrian
4
Chris's est en réalité supérieur puisqu'il fonctionne avec des chemins contenant des espaces. Lancer un vote à votre façon, mon pote.
Rbright
3
Moche, mais multi-plateforme :).
Voretaq7
62

@ Douglas Leeder, une autre réponse: triez la sortie lisible par l'homme de du -h à l'aide d'un autre outil. Comme 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)}<>;'

Divisé en deux lignes pour s'adapter à l'écran. Vous pouvez l'utiliser de cette façon ou en faire une ligne, cela fonctionnera dans les deux cas.

Sortie:

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

EDIT: Après quelques parties de golf à PerlMonks , le résultat final est le suivant:

perl -e'%h=map{/.\s/;99**(ord$&&7)-$`,$_}`du -h`;die@h{sort%h}'
Adam Bellaire
la source
2
Votre version courte est activée stderrcar dievous pouvez la modifier pour la rendre affichée stdout.
Dennis Williamson
2
Changer le dieen un printet il ira à stdout. C'est juste deux autres personnages.
Adam Bellaire
fonctionne sur Ubuntu!
marinara
hackistry perl impressionnant
nandoP
Le résultat est en ordre inverse :(
RSFalcon7
55

Ncdu est un outil extrêmement utile que j’utilise, qui est conçu pour rechercher ces dossiers et fichiers très chargés d’ usage disque, et pour les supprimer. Il est basé sur la console, rapide et léger, et propose des packages pour toutes les distributions principales.


la source
Très bien ... Je me demande si les résultats pourraient être alimentés à la norme ... Je suis tellement paresseux que je ne peux pas lire le manuel
ojblass
8
gt5 est dans la même veine; sa principale caractéristique est la croissance.
Tobu
1
C'est vraiment cool! Et beaucoup plus rapidement que de traîner avec du, si vous voulez juste identifier les grands annuaires.
BurninLeo
44
du -k * | sort -nr | cut -f2 | xargs -d '\n' du -sh
Jake Wilson
la source
Impossible d'utiliser avec du -k --total, donne une erreur à la findu: cannot access 'total': No such file or directory
laggingreflex
J'aime celui-ci plus toute autre réponse. comment iriez-vous pour ne montrer que les 50 premiers résultats?
Mau
1
@Mauro - il suffit de diriger le résultat headen ajoutant `| tête -50` à la fin.
Samuel Lelièvre
21

Autant que je sache, vous avez trois options:

  1. Modifiez dupour trier avant l'affichage.
  2. Modifiez sortpour prendre en charge les tailles humaines pour le tri numérique.
  3. Post-traitement de la sortie de tri pour modifier la sortie de base en lisible par l'homme.

Vous pouvez également faire du -ket vivre avec des tailles en KiB.

Pour l'option 3, vous pouvez utiliser le script suivant:

#!/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
la source
20

J'ai eu ce problème aussi et j'utilise actuellement une solution de contournement:

du -scBM | sort -n

Cela ne produira pas de valeurs mises à l'échelle, mais produira toujours la taille en mégaoctets. C'est moins que parfait, mais pour moi c'est mieux que rien (ou afficher la taille en octets).

Joachim Sauer
la source
J'aime le commutateur th -BM, qui est fondamentalement le même que -m, mais il présente l'avantage d'afficher la taille et le suffixe M, vous obtenez donc 10M, ce qui est beaucoup plus clair que 10 :)
Tom Feiner
C'est la solution la plus simple que j'ai vue jusqu'ici sur cette page, merci!
Jeff Olson
19

Trouvé cette annonce ailleurs. Par conséquent, ce script shell fera ce que vous voulez sans tout appeler dudeux fois. Il utilise awkpour convertir les octets bruts en un format lisible par l’homme. Bien entendu, le formatage est légèrement différent (tout est imprimé avec une précision d'une décimale).

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

Exécuter ceci dans mon .vimrépertoire donne:

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

(J'espère que 3,6 millions de combinaisons de couleurs ne sont pas excessives.)

Adam Bellaire
la source
1
J'ai aussi une réponse à Perl, mais je pense que cela pourrait amener les gens à me détester: du -B1 | trier -nr | perl -e '% h = (0 => b, 1 => K, 2 => M, 3 => G); pour (<>) {($ s, @ f) = scindé / \ 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
Même si la réponse Perl donne sa mise en forme beaucoup plus proche de du. Bien que l'arrondi soit éteint ... On dirait que du donne toujours ceil () plutôt que round ()
Adam Bellaire
Pourquoi ai-je utilisé un hash? Aurait dû être un tableau ... matin-cerveau grommeler ....
Adam Bellaire
Ajout d'une meilleure solution Perl comme autre réponse.
Adam Bellaire
Les deux versions échouent lorsque les noms de fichiers contiennent des espaces
Vi.
15

Cette version utilise awkpour créer des colonnes supplémentaires pour les clés de tri. Il appelle seulement duune fois. La sortie devrait ressembler exactement du.

Je l'ai divisé en plusieurs lignes, mais il peut être recombiné en une ligne.

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

Explication:

  • BEGIN - créez une chaîne à indexer pour substituer 1, 2, 3 à K, M, G pour le regroupement par unités. S'il n'y a pas d'unité (la taille est inférieure à 1K), il n'y a pas de correspondance et un zéro est renvoyé (parfait!). )
  • affiche les nouveaux champs - unité, valeur (pour que le tri alphabétique fonctionne correctement, il est rempli de zéros, de longueur fixe) et la ligne d'origine
  • indexe le dernier caractère du champ de taille
  • tirez la partie numérique de la taille
  • trier les résultats, éliminer les colonnes supplémentaires

Essayez-le sans la cutcommande pour voir ce qu'il fait.

Voici une version qui fait le tri dans le script AWK et qui n’a pas besoin de 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
la source
Merci! C'est le premier exemple qui fonctionne pour moi dans OS X 10.6 sans compter les scripts perl / phython. et merci encore pour la bonne explication. toujours agréable d'apprendre quelque chose de nouveau. awk est un outil puissant.
Wolf
Grand merci pour cela. J'ai changé le du pour du -sh *afficher uniquement les fichiers et les répertoires immédiats sans descente récursive.
HankCa
15

Voici un exemple montrant les répertoires sous une forme résumée plus compacte. Il gère les espaces dans le répertoire / noms de fichiers.

% 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
la source
1
Les utilisateurs de macOS / OSX doivent être avertis que la version mac de xargs ne prend pas en charge l'indicateur -d. Si vous l'omettez, les répertoires contenant un espace voient chaque mot analysé séparément, ce qui bien sûr échoue.
jasonologie
11

trier les fichiers par taille en Mo

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

J'ai un wrapper python simple mais utile pour du appelé dutop . Notez que nous (responsables de la maintenance de coreutils) envisage d’ajouter la fonctionnalité à trier pour trier directement la sortie "humaine".

pixelbeat
la source
1
+1 pour l’une des rares exceptions valides permettant de "faire une chose et le faire correctement". À moins que quelqu'un ne sache comprendre le préfixe SI et / ou les préfixes binaires.
Joachim Sauer
Et comme le mentionne ptman ci-dessous: ta da ! (nouveau sortdrapeau)
Tobu
9

En ai un autre:

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

Je commence à aimer Perl. Vous pourriez avoir à faire un

$ cpan Number::Bytes::Human

première. Pour tous les hackers de Perl: Oui, je sais que le tri peut également se faire en Perl. Probablement le du part aussi.

0x89
la source
8

Ce bout de code était sans vergogne de la part de Jean-Pierre à l' adresse http://www.unix.com/shell-programming-scripting/32555-du-h-sort.html . Y a-t-il un moyen de mieux le créditer?

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
la source
Je pense que si c'est un très grand nombre, alors l'unité est partie et le nombre affiché est petit ... try23423423432423
nopole
7

Utilisez le drapeau "-g"

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

Et sur mon répertoire / usr / local, le résultat est le suivant:

$ 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
la source
4
Cela ne donne toutefois pas une sortie lisible par l’homme, ce que le PO cherchait.
4

Un autre:

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
la source
4

Voici la méthode simple que j'utilise, très faible utilisation des ressources et obtenant ce dont vous avez besoin:

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
la source
4

Trouvé celui-ci en ligne ... semble fonctionner correctement

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
la source
Sur cette base, j’ai créé un script pour fournir une sortie du (1) lisible à l’homme et triée. Veuillez vous référer à ma réponse, serverfault.com/a/937459/218692 .
Tripp Kinetics
3

J'ai appris awk en concoctant cet exemple hier. Cela a pris du temps, mais c'était très amusant et j'ai appris à utiliser awk.

Il ne fonctionne qu'une fois, et son rendement est très proche de celui de -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 }'

Il montre des nombres inférieurs à 10 avec une décimale.

Marlar
la source
3

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

Patrick
la source
2

Si vous devez gérer des espaces, vous pouvez utiliser les méthodes suivantes

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

L'instruction sed supplémentaire aidera à résoudre les problèmes liés aux dossiers portant des noms tels que Support technique.

Chealion
la source
Je viens d'essayer cela sur macOS Sierra. Fonctionne comme prévu. Agréable!
jasonologie
1

Voilà:

du -sk /var/log/* | sort -rn | awk '{print $2}' | xargs -ia du -hs "a"
très lourd
la source
1

http://dev.yorhel.nl/ncdu

commande: ncdu

Navigation dans les répertoires, tri (nom et taille), graphique, lisible par l'homme, etc ...

Adam Eickhoff
la source
1
Excellent utilitaire, mais pas installé par défaut sur les systèmes d'exploitation à ma connaissance. Pas nécessairement un problème, mais encore un programme à surveiller ...
voretaq7
1

Une autre awksolution -

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
utilisateur96753
la source
1

J'utilisais la solution fournie par @ptman, mais un changement de serveur récent l'a rendue inutilisable. Au lieu de cela, j'utilise le script bash suivant:

#!/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
la source
La du -d 1syntaxe BSD est supportée par GNU du depuis la sortie de coreutils 8.6 en 2010 (bien que sa première disponibilité Red Hat soit RHEL 7 en 2014), vous n’avez donc plus besoin de cette solution --maxdepth=1. Je n'ai découvert cela récemment que moi-même.
Adam Katz
1

du -s * | trier -nr | cut -f2 | xargs du -sh

ageek2remember
la source
Ce n'est pas une bonne solution, car il traverse le système de fichiers deux fois.
Paul Gear
1

Il y a beaucoup de réponses ici, dont beaucoup sont des doublons. Je vois trois tendances: passer d'un second appel à un autre, utiliser un code shell / awk compliqué et utiliser d'autres langages.

Voici une solution compatible POSIX utilisant du et awk qui devrait fonctionner sur tous les systèmes.

J'ai adopté une approche légèrement différente, en ajoutant -xpour nous assurer de rester sur le même système de fichiers (je n'ai besoin de cette opération que lorsque je manque d'espace disque, alors pourquoi supprimer les éléments que j'ai montés dans cet arbre FS ou déplacés et symlinked back?) et l’affichage des unités constantes pour faciliter l’analyse visuelle. Dans ce cas, je choisis généralement de ne pas trier pour mieux voir la structure hiérarchique.

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

(Puisqu'il s'agit d'unités cohérentes, vous pouvez alors ajouter | sort -nsi vous voulez vraiment trier les résultats.)

Cela filtre tout répertoire dont le contenu (cumulatif) ne dépasse pas 512 Mo, puis affiche les tailles en giga-octets. Par défaut, du utilise une taille de bloc de 512 octets (si l'état de awk de 2 20 blocs est 512Mo et son 2 21 diviseur convertit les unités GB - nous pourrions utiliser du -kxavec $1 > 512*1024et s/1024^2d'être plus lisible par l' homme). Dans la condition awk, nous avons défini sla taille pour pouvoir la supprimer de la ligne ( $0). Ceci conserve le délimiteur (qui est réduit à un seul espace), ainsi la finale %sreprésente un espace puis le nom du répertoire agrégé. %7saligne la %.2ftaille arrondie en Go (augmentez à %8ssi vous avez> 10 To).

Contrairement à la plupart des solutions proposées ici, cela prend correctement en charge les répertoires avec des espaces dans leurs noms (même si chaque solution, y compris celle-ci, manipulera mal les noms de répertoires contenant des sauts de ligne).

Adam Katz
la source
0

Au moins avec les outils habituels, cela sera difficile à cause du format dans lequel les nombres sont lisibles par l'homme (notez que cette sorte fait un "bon travail" ici car elle trie les nombres - 508, 64, 61, 2, 2 - il ne peut tout simplement pas trier les nombres en virgule flottante avec un multiplicateur supplémentaire).

J'essaierais l'inverse - utiliser le résultat de "du | sort -n -r" et convertir ensuite les nombres en format lisible par l'homme avec un script ou un programme.

schnaader
la source
0

Ce que vous pouvez essayer, c'est:

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

J'espère que ça t'as aidé.

Witts chrétiens
la source
c'est ce que fait xargs ;-)
cadrian
héhé, j'oublie toujours xargs. ;) À la fin de la journée, tout ce qui permet de faire le travail imo.
MacOSX par défaut (c'est-à-dire en dehors de chez soi) ne prend pas en charge ce qui convient xargs, ce formulaire était donc nécessaire. Toutefois, pour les fichiers contenant des espaces, vous devez définir 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
la source