roXet has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to write a perl script to report the size of the subdirectories of a certian higher dir. I looked on perlmonks.org and from what I could gather -s $foo will report the size of a file, but I can't find any documentation on this. Like does this report bytes or kilobytes? Either way, it does not look to be right. Here is the code that I have so far, it is a reworking of some code I found on here to do a similar job.
#!/usr/bin/perl use strict; my $dir = '.'; my %directories = (); my $dirsRef = \%directories; &find_size($dir, $dirsRef); foreach my $key (sort keys %directories) { print "$key has $directories{$key} bytes in it\n"; } sub find_size { my ($currentDir, $dirsRef) = @_; opendir DIR, $currentDir; my @files = grep !/^\.\.?$/, readdir DIR; for my $blah (@files) { if (-d $blah) { &find_size($blah, $dirsRef); } else { $dirsRef->{$currentDir} += (-s $blah); } } }
Am I on the right track? Any suggestions are greatly appreciated.

Replies are listed 'Best First'.
Re: Find the size of sub dirs
by Fastolfe (Vicar) on Feb 10, 2001 at 02:38 UTC
      Thanks for pointing me in the right direction guys. I just finished the script (yeah it took me awhile, doing tech support sux0rs). Here is what I came up with, it's got some PM code in it along with mine. This was a quick hack to get it to do exctaly what I wanted, maybe the infinate wisdom of the Monks can clean it up some.
      #!/usr/bin/perl use strict; use File::Find; my $dir = shift; if (!$dir) {die "perl $0 [startdir]\n";} my @subdirs = (); my $subdirsRef = \@subdirs; my %size; &get_sub_dirs($dir, $subdirsRef); for my $foo (@subdirs) { $size{$foo} = (&dir_tree_size($foo)); } print "Subdirectory size report for $dir\n\n\n"; foreach my $key (sort keys %size) { print "$key = "; printf("%.3f", $size{$key}); print " K\n"; } print "\n\n"; sub get_sub_dirs { my ($dir, $arrayRef) = @_; opendir DIR, $dir; my @files = grep !/^\.\.?$/, readdir DIR; for my $i (@files) { if (-d $i) { push @$arrayRef, $i; } } } sub dir_tree_size { my $dir = shift; my ($i,$total); $total = 0; opendir DIR, $dir; my @files = grep !/^\.\.?$/, readdir DIR; for $i (@files) { if(-d $dir . "\\" . $i) { $total += &dir_tree_size($dir . "\\$i") } else { $total += -s $dir . "\\" . $i} } $total = $total / 1024; return $total; }
        Why are you useing File::Find if you're not actually using it? Your code could be reduced a lot if you used File::Find, and your code would be able to safely handle symlinks and other operating systems.

        If your behavior was a little simpler (relying on arguments instead of finding subdirs first):

        use File::Find; use strict; foreach my $dir (@ARGV) { my $total; find(sub { $total += -s }, $dir); print "$dir: $total\n"; }
        Preserving the behavior of your script (mostly):
        use File::Find; use File::Spec; use strict; my $cur = File::Spec->curdir; my $up = File::Spec->updir; foreach my $start (@ARGV) { my @dirs = &find_subdirs($start); foreach my $dir (@dirs) { my $total = 0; find sub { $total += -s }, $dir; printf "%-20s %d\n", $dir, $total; } print STDERR "$start: No subdirectories\n" unless @dirs; } sub find_subdirs { my $start = shift; unless(opendir(D, $start)) { warn "$start: $!\n"; next; } my @dirs = map { -d "$start/$_" && !-l "$start/$_" && $_ ne $cur && $_ ne $up ? "$start/$_" : () } readdir(D); closedir(D); @dirs; }
Re: Find the size of sub dirs
by runrig (Abbot) on Feb 10, 2001 at 03:15 UTC
    Here's what I once wrote (it was awhile ago, please be nice, but feel free to criticize :) so I could say 'dirsz *' and get a sorted list of directories and sizes (I would just point you to a page on IIUG where it resides, but it seems to be down right now, so I'll post this for now & remove it later):

    Update:deleted the code here, it is in the upd_stats bundle in the DBA tools section of IIUG.

Re: Find the size of sub dirs
by spaz (Pilgrim) on Feb 10, 2001 at 05:30 UTC
    On the off-chance that you're on a UNIX based system...
    du -ks * will give a list of all directores (including .) and their size in K (thus -k). If you have the GNU version of du(1), you can s/-k/-h/ to get Human readable output.

    Then again you're probably in a Win environment, aren't you?

    -- Dave
      Yeah, this will be run on a windows box. The network admin here wants to be able to check the size of web folders to make people aren't going over the allowed limit. This came up when we were talking about C++ programming, but I told him I could do it in Perl, but I considered trying to compile the 'du' source on my windows box.