1459

I need to get a list of human readable du output.

However, du does not have a "sort by size" option, and piping to sort doesn't work with the human readable flag.

For example, running:

du | sort -n -r 

Outputs a sorted disk usage by size (descending):

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

However, running it with the human readable flag, does not sort properly:

du -h | sort -n -r

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

Does anyone know of a way to sort du -h by size?

6

39 Answers 39

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

The following solution is similar to cadrian's original however this will only run 2 du commands as opposed to one du for each directory in the tree.

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

However Cardrian's solution is more robust as the above will not work for very heavily populated trees as it could exceed the limit on the size of the arguments passed to du

0

Here's my solution, a simple bash script that only calls du once, and shows you only directories of size 1 MB or larger:

#!/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

Why not throw another hat into the ring.... it's an old question, but here's an example that is (mostly) pure shell script (fwiw) -- i.e, just bash and no perl/python/awk/etc. So in that sense maybe it offers something new to the discussion (or not). It calculates file size just once, but prints in various units (my preference). (The un-simplified version includes getopts that excludes "GB" if unwanted.)

#!/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

This is the alias I have in my .profile

alias du='sudo du -xh --max-depth=1 | sort -h'

sort -h is what really helps here to the question asked.

Another useful options are du -x to stay on the same filesystem; also sudo helps not to see errors if there are directories that aren't world-readable. Also, I always do du --max-depth=1, then drill down further etc..

0

Sorts in descending order.

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

Loosely based on the logic in this one-liner, I wrote a script that provides a sorted human-readable du(1) output. Other than requiring the -h flag for human-readability, it requires no other non-POSIX-compatible commands.

It is available at https://github.com/pleappleappleap/sorted-human-du.

0

Yet another du script!

As there is already a lot of answer, I just post my own script there. I use from more than eight years now.

This could by run by

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

where

  • optional flag -b tell to use byte count instead of block count
  • optional path as 1st argument, current directory if default.
  • if no second argument given, minimal size to be printed is 256Mb.

The output could look like:

\___   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
...

There is the 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:-.}"

You may show script on my own site or download them there.

-2

Instead of raping du and friends, you can use ls alone to do what you want:

ls -1Ssh

That will print all files sorted by size written in human-readable form. The first line it prints is the total, if you want to get rid of it you can simply use

ls -1Ssh | tail -n +2

You can add the -r flag to ls if you want the files in the reversed order (from smallest to largest).

2
  • At least here, that doesn't work. houdini@clanspum:~/ > ls -1Ssh | grep clanspum 4.0K drwxr-xr-x 27 houdini users 4.0K 2010-02-15 12:35 clanspum/ 0 drwxr-xr-x 2 houdini users 77 2010-02-15 13:06 clanspum-s/ houdini@clanspum:~/ > du -sh clanspum/ 602M clanspum/
    – Bill Weiss
    Feb 23, 2010 at 20:40
  • 4
    ... pretend that was formatted correctly. Point is, it shows a directory as being "4.0K", while du -sh shows "602M". The latter is correct.
    – Bill Weiss
    Feb 23, 2010 at 20:40
1
2

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .