web-dev-qa-db-fra.com

Comment trier la sortie du -h par taille

J'ai besoin d'obtenir une liste de sortie lisible par l'homme.

Cependant, du n'a pas d'option "trier par taille" et le piping vers sort ne fonctionne pas avec l'indicateur lisible par l'homme.

Par exemple, exécuter:

du | sort -n -r 

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

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

Cependant, l'exécuter avec l'indicateur lisible par l'homme, ne se trie pas correctement:

du -h | sort -n -r

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

Quelqu'un connaît-il un moyen de trier du -h par taille?

1029
Tom Feiner

Depuis GNU coreutils 7.5 sorti en août 2009, sort autorise un paramètre -h, Qui autorise les suffixes numériques du type produit par du -h:

du -hs * | sort -h

Si vous utilisez un tri 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 sortmanuel :

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

1444
ptman
du | sort -nr | cut -f2- | xargs du -hs
89
cadrian

@Douglas Leeder, encore une réponse: Triez la sortie lisible par l'homme de du -h en utilisant 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)}<>;'

Fractionner sur deux lignes pour s'adapter à l'affichage. Vous pouvez l'utiliser de cette façon ou en faire une doublure, cela fonctionnera dans les deux sens.

Production:

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}'
62
Adam Bellaire

Il y a un outil extrêmement utile que j'utilise appelé ncd qui est conçu pour trouver ces dossiers et fichiers saturés à haute utilisation de disque et les supprimer. Il est basé sur une console, rapide et léger, et propose des packages sur toutes les principales distributions.

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

Autant que je sache, vous avez trois options:

  1. Modifiez du pour trier avant l'affichage.
  2. Modifiez sort pour prendre en charge les tailles humaines pour le tri numérique.
  3. Post-traiter la sortie de tri pour changer la sortie de base en lisible par l'homme.

Vous pouvez également faire du -k et 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
21
Douglas Leeder

J'ai également eu ce problème 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).

20
Joachim Sauer

Trouvé cette publication ailleurs. Par conséquent, ce script Shell fera ce que vous voulez sans appeler deux fois du sur tout. Il utilise awk pour convertir les octets bruts en un format lisible par l'homme. Bien sûr, 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 .vim le ré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 jeux de couleurs ne sont pas excessifs.)

19
Adam Bellaire

Cette version utilise awk pour créer des colonnes supplémentaires pour les clés de tri. Il n'appelle du qu'une seule fois. La sortie doit ressembler exactement à du.

Je l'ai divisé en plusieurs lignes, mais il peut être recombiné en un seul revêtement.

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 remplacer 1, 2, 3 par K, M, G pour le regroupement par unités, s'il n'y a pas d'unité (la taille est inférieure à 1K), alors il n'y a pas de correspondance et un zéro est renvoyé (parfait! )
  • imprimer les nouveaux champs - unité, valeur (pour que le tri alpha fonctionne correctement, il est rempli à zéro, de longueur fixe) et ligne d'origine
  • indexer le dernier caractère du champ taille
  • retirer la partie numérique de la taille
  • trier les résultats, éliminer les colonnes supplémentaires

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

Voici une version qui fait le tri dans le script AWK et 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]]}'

Voici un exemple qui montre 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
15
slm

trier les fichiers par taille en Mo

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

J'ai un simple python pour du appelé dutop . Notez que nous (les responsables de coreutils) envisage d'ajouter la fonctionnalité de tri pour trier "humain" sortie directement.

9
pixelbeat

J'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 devrez peut-être faire un

$ cpan Number::Bytes::Human

première. À tous les hackers de Perl: Oui, je sais que la partie de tri peut également être effectuée en Perl. Probablement le du part aussi.

9
0x89

Cet extrait a été éhonté de "Jean-Pierre" de http://www.unix.com/Shell-programming-scripting/32555-du-h-sort.html . Existe-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;
     }
    '
8
Bozojoe

Utilisez le drapeau "-g"

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

Et sur mon répertoire/usr/local produit une sortie comme celle-ci:

$ 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
7
Mick T

Trouvé celui-ci en ligne ... semble fonctionner 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
5
Peter Nunn

Voici la méthode simple que j'utilise, l'utilisation des ressources très faible et vous obtient 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
4
JacobN

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 s'exécute qu'une seule fois et a une sortie très similaire à 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 }'

Il affiche des nombres inférieurs à 10 avec un point décimal.

4
marlar

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

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

3
Patrick

Si vous devez gérer des espaces, vous pouvez utiliser les éléments suivants

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

L'instruction sed supplémentaire aidera à atténuer les problèmes avec les dossiers avec des noms tels que le support d'application

2
Chealion

Voilà:

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

Il y a beaucoup de réponses ici, dont beaucoup sont des doublons. Je vois trois tendances: passer par un deuxième appel du, utiliser du code Shell/awk compliqué et utiliser d'autres langages.

Voici une solution compatible POSIX utilisant d et awk qui devrait fonctionner sur chaque système.

J'ai adopté une approche légèrement différente, en ajoutant -x Pour 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 éliminer les éléments que j'ai montés dans ceci FS arbre ou déplacé et lié en retour?) et affichant des unités constantes pour faciliter l'analyse visuelle. Dans ce cas, je choisis généralement pas pour trier ainsi Je peux 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 }'

(Comme il s'agit d'unités cohérentes, vous pouvez ensuite ajouter | sort -n Si vous voulez vraiment des résultats sort ed.)

Cela filtre tout répertoire dont le contenu (cumulatif) ne dépasse pas 512 Mo, puis affiche les tailles en gigaoctets. Par défaut, du utilise une taille de bloc de 512 octets (donc la condition awk de 220 blocs est de 512 Mo et ses 221 diviseur convertit les unités en Go - nous pourrions utiliser du -kx avec $1 > 512*1024 et s/1024^2 pour être plus lisible par l'homme). À l'intérieur de la condition awk, nous définissons s à la taille afin de pouvoir le supprimer de la ligne ($0). Cela conserve le délimiteur (qui est réduit à un seul espace), donc le %s Final représente un espace, puis le nom du répertoire agrégé. %7s Aligne la taille arrondie de %.2f Go (augmentez à %8s Si vous avez> 10 To).

Contrairement à la plupart des solutions ici, cela prend correctement en charge les répertoires avec des espaces dans leurs noms (bien que every solution, y compris ceci un, va mal gérer les noms de répertoires contenant des sauts de ligne).

1
Adam Katz

Une autre awk solution -

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
user96753

http://dev.yorhel.nl/ncd

commande: ncdu

Navigation dans l'annuaire, tri (nom et taille), graphique, lisible par l'homme, etc ...

1
Adam Eickhoff

J'utilisais la solution fournie par @ptman, mais un récent changement de serveur l'a rendue non viable. 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);
}'
1
Keith Yoder

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

1
ageek2remember

Voici un exemple

du -h /folder/subfolder --max-depth=1 | sort -hr

Retour:

233M    /folder/subfolder
190M    /folder/subfolder/myfolder1
15M     /folder/subfolder/myfolder4
6.4M    /folder/subfolder/myfolder5
4.2M    /folder/subfolder/myfolder3
3.8M    /folder/subfolder/myfolder2

Vous pouvez également ajouter | head -10 pour rechercher les 10 premiers ou un nombre quelconque de sous-dossiers dans le répertoire spécifié.

1
ode2k

Ceci est l'alias que j'ai dans mon profil.

alias du = 'Sudo du -xh --max-depth = 1 | trier -h '

sort -h est ce qui aide vraiment ici à la question posée.

Une autre option utile est du -x pour rester sur le même système de fichiers; Sudo aide également à ne pas voir les erreurs s'il existe des répertoires qui ne sont pas lisibles par tous. Aussi, je fais toujours du --max-depth = 1, puis je descends plus loin, etc.

0
Tagar

Encore un autre script du!

Comme il y a déjà beaucoup de réponses, je poste juste mon propre script là-bas. J'utilise depuis plus de huit ans maintenant.

Cela pourrait être géré par

/somepath/rdu.sh [-b] [/somepath] [minSize]

  • drapeau optionnel -b dire d'utiliser nombre d'octets au lieu de block compter
  • facultatif chemin comme 1er argument, répertoire courant si par défaut.
  • si aucun deuxième argument n'est donné, la taille minimale à imprimer est 256Mb.

La sortie pourrait ressembler à:

\___   3.01G                 21.67%                .cache
|   \___   1.37G                 45.54%                mozilla
|   |   \___   1.37G                100.00%                firefox
|   |   |   \___ 581.71M                 41.48%                billiethek.default
|   |   |   |   \___ 522.64M                 89.85%                cache2
|   |   |   |   |   \___ 522.45M                 99.96%                entries
...

Il y a le script:

#!/bin/bash

if [ "$1" == "-b" ] ;then
    shift
    units=(b K M G T P)
    duargs="-xbs"
    minsize=${2:-$((256*1024**2))}
else
    units=(K M G T P)
    duargs="-xks"
    minsize=${2:-$((256*1024))}
fi

humansize() {
    local _c=$1 _i=0
    while [ ${#_c} -gt 3 ] ;do
        ((_i++))
        _c=$((_c>>10))
    done
    _c=$(( ( $1*1000 ) >> ( 10*_i ) ))
    printf ${2+-v} $2 "%.2f%s" ${_c:0:${#_c}-3}.${_c:${#_c}-3} ${units[_i]}
}
percent() {
    local p=000$((${1}00000/$2))
    printf ${3+-v} $3 "%.2f%%" ${p:0:${#p}-3}.${p:${#p}-3}
}

device=$(stat -c %d "${1:-.}")
printf -v sep "%16s" ""

rdu() {
    local _dir="$1" _spc="$2" _crt _siz _str _tot _pct
    while read _siz _crt;do
        if [ "$_crt" = "total"  ]; then
            _tot=$_siz
        else
            [ "$_tot" ] || _tot=$_siz
            if [ $_siz -gt $minsize ];then
                humansize $_siz _str
                percent $_siz $_tot _pct
                printf "%s\___ %7s%s%7s%s%s\n" \
                    "$_spc" $_str "$sep" $_pct "$sep" "${_crt##*/}"
                [ -d "$_crt" ] &&
                [ $(stat -c %d "$_crt") -eq $device ] &&
                rdu "$_crt" "|   $_spc"
            fi
        fi
    done < <(
        find "$_dir" -mindepth 1 -maxdepth 1 -xdev \
            \( -type f -o -type d \) -printf "%D;%p\n" |
            sed -ne "s/^${device};//p" |
            tr \\n \\0 |
            xargs -0 du ${duargs}c |
            sort -nr
    )
}

rdu "${1:-.}"

Et non, je ne les posterai pas sur Git***.xxx.

Vous pouvez les montrer là-bas ou télécharger le script là-bas.

0
F. Hauri

Voici ma solution, un simple script bash qui n'appelle du une fois et ne vous montre que les répertoires de taille 1 Mo ou plus:

#!/bin/env bash
# Usage: my_du.sh [subdirectory levels]
#   For efficiency, only calls "du" once, and stores results in a temp file
#   Stephen Becker, 2/23/2010

if [ $# -gt 0 ]; then
# You may prefer, as I do, to just summarize the contents of a directory
# and not view the size of its subdirectories, so use this:
    du -h --max-depth $1 > temp_du_file
else
    du -h > temp_du_file
fi


# Show all directories of size > 1 GB:
cat temp_du_file | grep "^\([0-9]\|\.\)\+G" | sort -nr
# Show all directories of size > 1 MB:
cat temp_du_file | grep "^\([0-9]\|\.\)\+M" | sort -nr

rm temp_du_file
0
Stephen

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

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

0
schnaader

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 cela pourra aider.

0
Christian Witts
du | sort -nr | awk '{ cmd = "du -h -d0 "$2"| cut -f1"; cmd | getline human; close(cmd); print human"\t"$2 }'
0
Nathan de Vries

La solution suivante est similaire à l'original de cadrian mais cela n'exécutera que 2 commandes du par opposition à un du pour chaque répertoire de l'arborescence.

du -hs `du |sort -g |cut -f2- `

Cependant, la solution de Cardrian est plus robuste car ce qui précède ne fonctionnera pas pour les arbres très peuplés car elle pourrait dépasser la limite de la taille des arguments transmis à du

0
Steve Weet

Librement basé sur la logique de ce one-liner , j'ai écrit un script qui fournit une sortie triée lisible par l'homme (1). Autre que d'exiger le -h indicateur de lisibilité, il ne nécessite aucune autre commande non compatible POSIX.

Il est disponible sur https://github.com/pleappleappleap/sorted-human-d .

0
Tripp Kinetics

Pourquoi ne pas jeter un autre chapeau sur le ring ... c'est une vieille question, mais voici un exemple qui est (principalement) un script Shell pur (fwiw) - c'est-à-dire, juste bash et pas Perl/python/awk/etc. Donc, dans ce sens, cela offre peut-être quelque chose de nouveau à la discussion (ou pas). Il calcule la taille du fichier une seule fois, mais imprime dans différentes unités (ma préférence). (La version non simplifiée inclut des getopts qui excluent "GB" si non souhaité.)

#!/bin/bash

printf -- ' %9s %9s %9s       %-30s\n' 'K'        'M'        'G'        'Path'
printf -- ' %9s %9s %9s       %-30s\n' '--------' '--------' '--------' '-----------'
du -sk "$@" | while read val; do
    file=$(echo "$val" | cut -f2-)
    size_k=$(echo "$val"  | cut -f1)
    printf ' %9s %9s %9s       %-30s\n' \
          ${size_k}  \
          $(( size_k / 1024 ))  \
          $(( size_k / 1024 / 1024 ))  \
          "$file"
  done | sort -n
0
michael

Trie par ordre décroissant.

du -s ./* | sort -n| cut -f 2-| xargs du -sh {}
0
Peter Nduati