Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

How do you sort du -sh /dir/* by size? I read one site that said use | sort -n but that's obviously not right. Here's an example that is wrong.

[~]# du -sh /var/* | sort -n
0       /var/mail
1.2M    /var/www
1.8M    /var/tmp
1.9G    /var/named
2.9M    /var/run
4.1G    /var/log
8.0K    /var/account
8.0K    /var/crash
8.0K    /var/cvs
8.0K    /var/games
8.0K    /var/local
8.0K    /var/nis
8.0K    /var/opt
8.0K    /var/preserve
8.0K    /var/racoon
12K     /var/aquota.user
12K     /var/portsentry
16K     /var/ftp
16K     /var/quota.user
20K     /var/yp
24K     /var/db
28K     /var/empty
32K     /var/lock
84K     /var/profiles
224M    /var/netenberg
235M    /var/cpanel
245M    /var/cache
620M    /var/lib
748K    /var/spool
share|improve this question
2  
I knew I'd seen this before. The highest-voted answer there isn't very good, but others are better. –  Gilles Dec 9 '10 at 20:11

11 Answers 11

up vote 46 down vote accepted

You can use du -sh * | sort -h. This tells sort that the input is the human-readable format.

This feature was added recently to GNU Core Utilities 7.5 in Aug 2009, so many distributions do not yet have it.

share|improve this answer
6  
note: add -r to sort, if you want the big ones at the top –  xenoterracide Dec 9 '10 at 12:52
3  
There's no sort -h on, eg OS X. Is that a GNU extension? –  alex Dec 9 '10 at 12:55
    
On Ubuntu 10.04, the -h is also non-existant. –  Gert Dec 9 '10 at 14:32
5  
It's in GNU Core Utilities since Aug 2009: savannah.gnu.org/patch/?func=detailitem&item_id=2565 The original patch was submitted in Feb 2004 –  Shawn J. Goff Dec 9 '10 at 15:29
1  
This feature is included with GNU Coreutils 7.5+. Ubuntu 10.04 ships with coreutils 7.4, but Maverick includes 8.5. –  Stefan Lasiewski Dec 9 '10 at 22:42

This little Perl script does the trick. Save it as duh (or whatever you want) and call it with duh /dir/*

#!/usr/bin/perl -w
use strict;

my @line;

sub to_human_readable {
        my ($number) = @_;
        my @postfix = qw( k M G T P );
        my $post;
        my $divide = 1;
        foreach (@postfix) {
                $post = $_;
                last if (($number / ($divide * 1024)) < 1);
                $divide = $divide * 1024;
        }
        $number = int($number/$divide + 0.5);
        return $number . $post;
}

sub trimlengthright {
        my ($txt, $len) = @_;
        if ( length($txt) >= $len ) {
                $txt = substr($txt,0,$len - 1) . " ";
        } else {
                $txt = $txt . " " x ($len - length($txt));
        }
        return $txt;
}

sub trimlengthleft {
        my ($txt, $len) = @_;
        if ( length($txt) >= $len ) {
                $txt = substr($txt,0,$len - 1) . " ";
        } else {
                $txt = " " x ($len - length($txt)) . $txt;
        }
        return $txt;
}

open(DF,"du -ks @ARGV | sort -n |");
while (<DF>) {
        @line = split;
        print &trimlengthleft(&to_human_readable($line[0]),5)," "; # size
        print &trimlengthright($line[1],70),"\n"; # directory
}
close DF;
share|improve this answer

Try using the -k flag to count 1K blocks intead of using human-readable. Then, you have a common unit and can easily do a numeric sort.

du -ck | sort -n

You don't explictly require human units, but if you did, then there are a bunch of ways to do it. Many seem to use the 1K block technique above, and then make a second call to du.

http://serverfault.com/questions/62411/how-can-i-sort-du-h-output-by-size

share|improve this answer

If you don't have sort -h you can do this:

du -sh * | sed 's/\([[:digit:]]\)\t/\1B\t/' | sed 's/\(.\t\)/\t\1/' | sed 's/G\t/Z\t/' | sort -n -k 2d,2 -k 1n,1 | sed 's/Z\t/G\t/'

This gets the du list, separates the suffix, and sorts using that. Since there is no suffix for <1K, the first sed adds a B (for byte). The second sed adds a delimiter between the digit and the suffix. The third sed converts G to Z so that it's bigger than M; if you have terabyte files, you'll have to convert G to Y and T to Z. Finally, we sort by the two columns, then we replace the G suffix.

share|improve this answer

If you don't have a recent version of GNU coreutils, you can call du without -h to get sortable output, and produce human-friendly output with a little postprocessing. This has the advantage of working even if your version of du doesn't have the -h flag.

du -k | sort -n | awk '
    function human(x) {
        s="kMGTEPYZ";
        while (x>=1000 && length(s)>1)
            {x/=1024; s=substr(s,2)}
        return int(x+0.5) substr(s,1,1)
    }
    {gsub(/^[0-9]+/, human($1)); print}'

If you want SI suffixes (i.e. multiples of 1000 rather than 1024), change 1024 to 1000 in the while loop body. (Note that that 1000 in the condition is intended, so that you get e.g. 1M rather than 1000k.)

If your du has an option to display sizes in bytes (e.g. -b or -B 1 — note that this may have the side effect of counting actual file sizes rather than disk usage), add a space to the beginning of s (i.e. s=" kMGTEPYZ";), or add if (x<1000) {return x} else {x/=1024} at the beginning of the human function.

Displaying a decimal digit for numbers in the range 1–10 is left as an exercise to the reader.

share|improve this answer

Here's what I use on Ubuntu 10.04, CentOS 5.5, FreeBSD and Mac OS X.

I borrowed the idea from www.geekology.co.za/ and earthinfo.org, as well as the infamous ducks from "Linux Server Hacks" by O'Reilly. I am still adapting it to my needs. This is still a work in progress (As in, I was working on this on the train this morning.):

#! /usr/bin/env bash
ducks () {
    du -cks -x | sort -n | while read size fname; do
        for unit in k M G T P E Z Y; do
            if [ $size -lt 1024 ]; then
                echo -e "${size}${unit}\t${fname}"
                break
            fi
            size=$((size/1024))
        done
    done
}
ducks > .ducks && tail .ducks

Here's the output:

stefan@darwin:~ $ ducks
32M src
42M .cpan
43M .macports
754M    doc
865M    Work
1G  .Trash
4G  Library
17G Downloads
30G Documents
56G total

stefan@darwin:~ $
share|improve this answer

Go crazy with this script -

$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;}'
share|improve this answer

To sort by size in MB

du --block-size=MiB --max-depth=1 path | sort -n
share|improve this answer
    
The user wants to get the output of du -h (human readable output) sorted numerically. You're not providing an answer to that. You may also want to link your UNIX-SE account with the other accounts you have on the other SE sites. –  Tonin Mar 11 '13 at 11:58

This script is even easier:

for i in G M K; do du -h -d1 / | grep [0-9]$i | sort -n; done
share|improve this answer

On OS X, you can install the needed coreutils via Homebrew:

brew install coreutils

With this you'll have gsort, which includes the -h command line parameter.

share|improve this answer

This one handles filenames with whitespace or apostrophes, and works on systems which do not support xargs -d or sort -h:

du -s * | sort -n | cut -f2 | tr '\n' '\0' | xargs -0 -I {} du -sh "{}"

which results in:

368K    diskmanagementd
392K    racoon
468K    coreaudiod
472K    securityd
660K    sshd
3.6M    php-fpm
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.