#!/usr/bin/perl -w
use strict;
# like du, but lets you filter out files & directories less than x bytes.
# default filtering is 10M, default depth is 10.
# also, by default the files are sorted by size from greatest to least.
my @ts = ();
for my $file (@ARGV) {
push $ts, handle_path($file);
}
print_paths(\@ts, 0);
=name handle_path
given an input path returns a tuple [name, size, contents]
where contents is a list-ref of the same sort of tuples for all contents of path
(assuming path is a directory). If path is not a directory, contents is [].
=cut
sub handle_path {
my $path = shift;
my $total = 0;
my @ret = ();
my @contents = ();
# First build up the "contents" tuple-list.
# For each subdir, call handle_path.
if (-d $path) {
opendir DIR, $path;
while ($subdir =
) {
my $t = handle_path("$path/$subdir");
$total += $t->[1];
push @contents, $t;
}
closedir DIR;
} else {
$total = lstat($path)[7];
}
$ret[0] = $path;
$ret[1] = $total;
$ret[2] = \@contents;
return \@ret;
}
=name print_paths
Takes an array-ref. Sorts it by filesize and prints each item, recursing when it has children.
=cut
sub print_paths {
my $ts = shift;
my $depth = shift;
my @sorted = reverse sort { $a->[1] <=> $b->[1] } @$ts;
for my $t (@sorted) {
my $ab = sprintf("%4s", abbrev($t->[1]));
print ("\t" x $depth), $ab, "\t", $t->[0], "\n";
print_paths($t->[2], $depth + 1) if $t->[2];
}
}
sub abbrev {
my $val = shift;
# TODO: don't include a . unless < 10
if ($val >= 1000000000000000) {
return sprintf("%0.1fP", $val / 1000000000000000);
} elsif ($val >= 1000000000000) {
return sprintf("%0.1fT", $val / 1000000000000);
} elsif ($val >= 1000000000) {
return sprintf("%0.1fG", $val / 1000000000);
} elsif ($val >= 1000000) {
return sprintf("%0.1fM", $val / 1000000);
} elsif ($val >= 1000) {
return sprintf("%0.1fK", $val / 1000);
} else {
return "${val}B";
}
}