#!/usr/bin/perl use strict; use warnings; use constant ONEOVERLOG2 => 1/log(2); use File::Find; use Template; my %sums; ## $sums{$uid}[$log_2_blocks]{blocks} += $blocks; ## $sums{$uid}[$log_2_blocks]{count} ++; @ARGV = qw(.) unless @ARGV; my %seen; find sub { return if -l; return unless -f _ or -d _; my @stat = stat(_) or return; my ($dev, $ino, $uid, $blocks) = @stat[0, 1, 4, 12]; return if $seen{"$dev $ino"}++; my $slot = $blocks ? log($blocks) * ONEOVERLOG2 : 0; $sums{$uid}[$slot]{blocks} += $blocks; $sums{$uid}[$slot]{count}++; }, @ARGV; my %usernames = map { $_ => scalar getpwuid $_ } keys %sums; my @labels; for (values %sums) { while (@labels < @$_) { push @labels, 2**@labels; } } my %VARS = (sums => \%sums, usernames => \%usernames, labels => \@labels); Template->new({ POST_CHOMP => 1 }) ->process(\<<'END_OF_TEMPLATE', \%VARS) or die Template->error; [% BLOCKSIZE = 1024 %] [% MACRO nice(n) BLOCK; IF n >= 1073741824 * 9.995; n / 1073741824 | format('%dG'); ELSIF n >= 1073741824; n / 1073741824 | format('%.2gG'); ELSIF n >= 1048576 * 9.995; n / 1048576 | format('%dM'); ELSIF n >= 1048576; n / 1048576 | format('%.2gM'); ELSIF n >= 1024 * 9.995; n / 1024 | format('%dK'); ELSIF n >= 1024; n / 1024 | format('%.2gK'); ELSE; n; END; END %] [% MACRO bc(b,c) BLOCK %] [% bytes = b * BLOCKSIZE; nice(bytes) %]
[% nice(c) %] [% END %] [% FOR uid = sums.keys.nsort %] [% IF loop.first %] [% FOR label = labels %] [% IF loop.first %] [% END %] [% IF loop.last %] [% END %] [% END %] [% END %] [% labels_max = labels.max %] [% FOR column = [0..labels_max] %] [% cell = sums.$uid.$column %] [% IF loop.first %] [% total_blocks = 0; total_count = 0 %] [% END %] [% IF cell %] [% total_blocks = total_blocks + cell.blocks %] [% total_count = total_count + cell.count %] [% bc(cell.blocks, cell.count) %] [% ELSE %] [% END %] [% IF loop.last %] [% bc(total_blocks, total_count) %] [% END %] [% END %] [% IF loop.last %]
User[% label_bytes = label * BLOCKSIZE; nice(label_bytes) %]Total
[% usernames.$uid || "?"; " ("; uid; ")" %] 
[% END %] [% END %] END_OF_TEMPLATE