Sign up ×
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
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

13 Answers 13

up vote 79 down vote accepted

If you have GNU coreutils (common in most Linux distributions), you can use du -sh * | sort -h. The -h option tells sort that the input is the human-readable format (number with unit).

This feature was added to GNU Core Utilities 7.5 in Aug 2009.


If you are using Mac OSX, you need install coreutils with brew install coreutils, then use gsort as drop-in replacement of sort

share|improve this answer
note: add -r to sort, if you want the big ones at the top – xenoterracide Dec 9 '10 at 12:52
On OSX you can install coreutils via brew and add the bin folder to your PATH into your rc file, and -h should be available. – kenorb Mar 5 at 14:20

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.

If you want to see the KB units added, use:

du -k | sed -e 's_^\([0-9]*\)_\1 KB_' | sort -n
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) {
        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

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
Awesome effort, but this doesn't come close to working for me. – jvriesem Sep 3 at 2:55

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

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

Since Mac OS X doesn't have the -h option for sort, so I tried and learned sed and awk for a first attempt:

du -sk * | sort -g | awk '{ numBytes = $1 * 1024; numUnits = split("B K M G T P", unit); num = numBytes; iUnit = 0; while(num >= 1024 && iUnit + 1 < numUnits) { num = num / 1024; iUnit++; } $1 = sprintf( ((num == 0) ? "%6d%s " : "%6.1f%s "), num, unit[iUnit + 1]); print $0; }'

it is a long line. Expanded, it is:

du -sk * | sort -g | awk '{ 

    numBytes = $1 * 1024; 
    numUnits = split("B K M G T P", unit); 
    num = numBytes; 
    iUnit = 0; 

    while(num >= 1024 && iUnit + 1 < numUnits) { 
        num = num / 1024; 

    $1 = sprintf( ((num == 0) ? "%6d%s " : "%6.1f%s "), num, unit[iUnit + 1]);
    print $0; 


I tried it on Mac OS X Mavericks, Yosemite, Ubuntu 2014-04 with awk being the default awk (which is nawk, because both awk and nawk point to /usr/bin/mawk) or gawk, and they all worked.

Here is a sample of the output on a Mac:

     0B  bar
     0B  foo
   4.0K  wah
  43.0M  Documents
   1.2G  Music
   2.5G  Desktop
   4.7G  Movies
   5.6G  VirtualBox VMs
   9.0G  Dropbox
  11.7G  Library
  21.2G  Pictures
  27.0G  Downloads

instead of du -sk *, I saw in @Stefan's answer where the grand total is also displayed, and without traversing any filesystem mount point, by using du -skcx *

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 and, 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}"
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
I think you meant du -cks -x * ? (with the asterisk) – 太極者無極而生 Apr 22 at 9:02
The asterisk is redundant in this usage. Give it a try. – Stefan Lasiewski Apr 22 at 18:39
do you mean putting the first set of code into a file called ducks, and then chmod a+x ducks and then use ./ducks to run it? Then I only see the total disk usage, on both Mac OS X and on Ubuntu 2014-10. I also tried putting the ducks() { ...} definition into .bashrc and then use ducks to run it, and the same thing on Mac OS X, only see the grand total – 太極者無極而生 Apr 23 at 7:20

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

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

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

for OSX

du -h -k  {PATH} | sort -n
share|improve this answer
isn't the -k just cancelling -h and if so how does this provide the human readable output requested by the OP. – Anthon Oct 10 at 7:58

Your Answer


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.