Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

A du(1) real-time sorter using Curses

by brian_d_foy (Abbot)
on Sep 03, 2004 at 07:48 UTC ( [id://388218]=CUFP: print w/replies, xml ) Need Help??

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>

Replies are listed 'Best First'.
Re: A du(1) real-time sorter using Curses
by tachyon (Chancellor) on Sep 03, 2004 at 10:53 UTC

    Cute. I wanted to be able to specify the dir root and use KB for file size:

    [root@devel3 root]# diff dutest dutest.patch 3c3,5 < open my( $pipe ), "du -a |"; --- > use constant UNITS => 1024; > my $dir = $ARGV[0] || '.'; > open my( $pipe ), "du -ab $dir |"; 131c133 < $win->addstr( $i, 1, sprintf( "%8d", $self->[$i][SIZE] || ' +' ) ); --- > $win->addstr( $i, 1, sprintf( "%8d", ($self->[$i][SIZE] || +0)/main::UNITS ) ); [root@devel3 root]#

    cheers

    tachyon

Re: A du(1) real-time sorter using Curses
by Paladin (Vicar) on Sep 03, 2004 at 15:42 UTC
    Small bug in the name method.

    Change

    my $index = shift || -1;
    to
    my $index = shift; $index = -1 unless defined $index;
    as 0 is a valid input for the name method to get the name of element 0
Re: A du(1) real-time sorter using Curses
by tachyon (Chancellor) on Sep 04, 2004 at 01:47 UTC

    A one line patch so you don't have to see the cursor racing around the screen

    *************** *** 37,42 **** --- 39,45 ---- my $self = shift; initscr; + curs_set(0); # hide cursor $win = Curses->new; for( my $i = MAX; $i >= 0; $i-- ) ***************

    cheers

    tachyon

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2024-04-20 11:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found