http://www.perlmonks.org?node_id=388218

A long time ago, when Kurt Starsinic and I worked in the same office, he wrote a little script to capture the output of du(1) and display only the largest sizes on the screen, and to do it as the results came in, not after du(1) finished. You only have to see the output that matters.

The trick is to use Curses and only remember the largest sizes. It was pretty cool then and it's still pretty cool.

I keep losing the script, though, because I never bothered to copy it to any new machines I got. I think this is the third time that I've rewritten the script, and only because I'm up late at night and I don't want to work on anything useful.

Maybe if I have too much free time on some other night I'll generalize this a bit more. Most of the heavy lifting doesn't care anything about du(1): it just knows it has a number and a string, and it sorts by the number. With a little anonymous sub magic, that number can be anything but formatted differently for display, say, a unix epoch time and a human readable date for sorting a bunch of files by modification time.

Enjoy.

#!/usr/bin/perl open my( $pipe ), "du -a |"; my $files = Local::lines->new; while( <$pipe> ) { chomp; my( $size, $file ) = split /\s+/, $_, 2; next if -d $file; next if $file eq "."; $files->add( $size, "$file" ); } package Local::lines; use Curses; use vars qw($win %rindex); use constant MAX => 24; use constant SIZE => 0; use constant NAME => 1; use Data::Dumper qw(Dumper); sub new { my $self = bless [], __PACKAGE__; $self->init(); return $self; } sub init { my $self = shift; initscr; $win = Curses->new; for( my $i = MAX; $i >= 0; $i-- ) { $self->size( $i, undef ); $self->name( $i, '' ); } } sub DESTROY { endwin; } sub add { my $self = shift; my( $size, $name ) = @_; # add new entries at the end if( $size > $self->size( MAX ) ) { $self->last( $size, $name ); $self->sort; } $self->draw(); } sub sort { my $self = shift; no warnings; $self->elements( sort { $b->[SIZE] <=> $a->[SIZE] } $self->elements ); %rindex = map { $self->name( $_ ), $_ } 0 .. MAX - 1; } sub elements { my $self = shift; if( @_ ) { @$self = @_ } @$self; } sub size { my $self = shift; my $index = shift || -1; if( @_ ) { $self->[$index][SIZE] = shift } $self->[$index][SIZE] || 0; } sub name { my $self = shift; my $index = shift || -1; if( @_ ) { $self->[$index][NAME] = shift } $self->[$index][NAME] || ''; } sub last { my $self = shift; if( @_ ) { $self->size( -1, shift ); $self->name( -1, shift || '' ); } ( $self->size( -1 ), $self->name( -1 ) ); } sub draw { my $self = shift; for( my $i = 0; $i < MAX; $i++ ) { next if $self->size( $i ) == 0 or $self->name( $i ) eq ''; $win->addstr( $i, 1, " " x $Curses::COLS ); $win->addstr( $i, 1, sprintf( "%8d", $self->[$i][SIZE] || '' +) ); $win->addstr( $i, 10, $self->name( $i ) ); $win->refresh; } }
--
brian d foy <bdfoy@cpan.org>