Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

du -h, sorted

by bellaire (Hermit)
on Feb 25, 2009 at 19:26 UTC ( #746356=CUFP: print w/replies, xml ) Need Help??

A humble offering, hoping to find a place where its perlishness won't be scorned. On another site, I got a little obsessed with this question I came across: How can I get sorted, human-readable output from du? It doesn't have a sort option, so you have to pass it to another program, like sort:
du | sort -nr
But if you want human-readable output, you can't do that, because sort can't sort it numerically. Others were offering shell solutions that invoked du on each item twice, once before being passed through sort, and once after for the human-readable verison. Wasteful! After finding solution in Awk, I wrote this "one-liner":
du -B1 | sort -nr | perl -e '@h=qw(b K M G);for(<>){($s,@f)=split/\s+/ +;$e=3;$e-- while(1024**$e>$s);$v=($s/(1024**$e));printf "%-8s%s\n",sp +rintf($v>=100?"%d%s":"%.1f%s",$v,$h[$e]),@f;}'
But then I realized it'd probably be better to use Perl for the sorting, and got this shorter result:
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)}<>;'
Both of them return human-readable disk usage output, sorted largest item first:
4.4M . 3.6M ./colors 372K ./plugin 128K ./autoload 100K ./syntax 100K ./doc
I almost posted this to the 'Obfuscation' area, but I thought this would be more appropriate. I am prepared to do penance if I was mistaken.

Update: Thanks to hbm, grinder, and Roy Johnson, a significantly smaller version has been golfed (putting it here because it's buried around ^7 in the comments):
perl -e'%h=map{/.\s/;99**(ord$&&7)-$`,$_}`du -h`;die@h{sort%h}'

Replies are listed 'Best First'.
Re: du -h, sorted
by grinder (Bishop) on Feb 25, 2009 at 21:56 UTC
    But then I realized it'd probably be better to use Perl for the sorting, and got this shorter result

    Now that sounds like a challenge...

    ... 90 88 characters.

    • another intruder with the mooring in the heart of the Perl

      Are you sure yours gets correct results? I'm getting 372K between 4.4M and 3.6M.
      perl -e 'sub c{pop=~/[GMK]/;ord($&)&7}print sort{c($b)<=>c($a)or$b<=>$ +a}`du -h`'

      Caution: Contents may have been coded under pressure.

        You're absolutely correct. Allow me to replace it by the following, clocking in at 87.

        perl -e'sub h{pop=~/(...)(.)/&&{M,1e3,G,1e6}->{$2}+$1}print sort{h($b) +<=>h$a}`du -h`'

        update: No wait! There's something in your idea of bitanding... Just have to get rid of the second spaceship comparator...

        perl -e'sub c{pop=~/[GMK]/;(ord$&&7).1e3+$`}print sort{c($b)<=>c$a}`du + -h`'

        76 strokes.

        • another intruder with the mooring in the heart of the Perl

      I like your subtle omission of parens from h$a, versus h($b). But to sort correctly, I tweaked slightly to use the OP's 10,20,30 values.
      perl -e 'sub h{pop=~/(...)(.)/&&$1*2**{K,10,M,20,G,30}->{$2}}print sor +t{h($b)<=>h$a}`du -h`'
Re: du -h, sorted
by Tanktalus (Canon) on Feb 27, 2009 at 00:48 UTC

    Honestly, though, I'd skip du, and just use cog's FileSys::DiskUsage module. It wouldn't be as short, but it'd be, um, a bit more readable ;-)

    #! /usr/bin/perl use strict; use warnings; use Filesys::DiskUsage qw(du); use Sort::Key qw(ikeysort); my @files = @ARGV ? @ARGV : glob '*'; my %sizes = du( { 'make-hash' => 1, 'recursive' => 0, 'sector-size' => 1024, }, @files); @files = ikeysort { $sizes{$_} } keys %sizes; my %config = ( human => 1, 'truncate-readable' => 2 ); printf "%8s %s\n", Filesys::DiskUsage::_convert($sizes{$_}, %config), $_ for @files;
    But, that's just me. (And look at all the other cool things you can do with Filesys::DiskUsage, or even the output format!

Re: du -h, sorted
by hbm (Hermit) on Feb 27, 2009 at 17:56 UTC

    I can't stop looking at this unbeliev unbellairevable one-liner! Alas, in your Update, you went from 7**(ord$&&30) to 99**(ord$&&7), and the new one mis-sorts empty files.

    And I can eke out one last character in a reversed sort:

    perl -e '%h=map{/.\s/;7x(ord$&&10)+$`,$_}`du -h`;die@h{sort%h}'
Re: du -h, sorted
by DrHyde (Prior) on Feb 26, 2009 at 11:01 UTC
    +1, useful

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://746356]
Front-paged by grinder
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2022-05-25 13:57 GMT
Find Nodes?
    Voting Booth?
    Do you prefer to work remotely?

    Results (90 votes). Check out past polls.