[forwarded submission from a non-member address -- rjk]


From: Bob Rogers <[EMAIL PROTECTED]>
Date: Wed, 24 Jul 2002 09:10:25 -0400
Subject: Re: [Boston.pm] getting a directory size
To: Erik Price <[EMAIL PROTECTED]>
CC: "Steve Linberg" <[EMAIL PROTECTED]>,
   "[EMAIL PROTECTED]" <[EMAIL PROTECTED]>


   From: "Steve Linberg" <[EMAIL PROTECTED]>
   Date: Wed, 24 Jul 2002 02:03:22 -0400 (EDT)

   On Wed, 24 Jul 2002, Erik Price wrote:

   > Is there a 
   > command or something that can recursively determine the amount of disk 
   > space "contained" in a directory that I can use in this pipe?

   du -s -k dir_name

   (du = "disk usage" on some *nixen)

But note that not all of them understand "-k"; if they don't, you
probably don't need it.

   Here's a minimal script I wrote (a while ago, it seems) to do "du" by
user, back when we were having quota problems.  Using a pipe would
undoubtedly be more efficient, but this should give you some ideas in
case "du" doesn't do quite what you want (or you're not using Unix).

                                        -- Bob Rogers
                                           http://rgrjr.dyndns.org/


#!/usr/local/bin/perl
#
# du by user.  [doesn't properly account for hard links, though.  -- rgr,
# 15-Jun-98.]
#
#    Modification history:
#
# created.  -- rgr, 15-Jun-98.
#

sub user_name {
    my $uid = shift;

    $uid_to_user_name{$uid}
      || ($uid_to_user_name{$uid} = getpwuid($uid));
}

sub du_dir {
    my ($dir, $parent_size) = @_;
    my ($file, $uid, %size, $subdir, @subdirs);

    opendir(DIR, $dir) || die;
    while ($file = readdir(DIR)) {
        chomp($file);
        next if $file eq '..';  # we don't own our parent directory.
        my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 
            $atime, $mtime, $ctime, $blksize, $blocks)
            = lstat("$dir/$file");
        $size{$uid} += $blocks;
        $size{'total'} += $blocks;
        # print(join("\t", "$dir/$file", $size, $blocks, sprintf('%o', $mode)), "\n");
        if ($mode & oct(40000) && $file ne '.') {
            push(@subdirs, "$dir/$file");
        }
    }
    closedir(DIR);
    # Recur into subdirectories, in what is effectively a preorder traversal.
    # Do this *after* we are through with DIR, because directory filehandles are
    # globally scoped.  -- rgr, 15-Jun-98.
    foreach $subdir (@subdirs) {
        du_dir($subdir, \%size);
    }
    # Report results.
    $size = sprintf('%d', ($size{'total'}+1)/2);
    print("$size\t$dir");
    foreach $uid (sort(keys(%size))) {
        $ {$parent_size}{$uid} += $size{$uid};
        unless ($uid eq 'total') {
            $size = sprintf('%d', ($size{$uid}+1)/2);
            print("\t$size\t", user_name($uid));
        }
    }
    print "\n";
}

push(@ARGV, '.') unless @ARGV;
%size = ();
foreach $arg (@ARGV) {
    du_dir($arg, \%size)
        if -d $arg;
}

Reply via email to