Calculate directorysize from a list?

Discussion in 'Perl Misc' started by Math55, Jul 29, 2003.

  1. Math55

    Math55 Guest

    hi, i have the follwoing list.


    ----

    528k /tmp/icons/4599-OS-X-GamePak.tar.gz
    244k /tmp/icons/4780-OS-Logos.tar.gz
    744k /tmp/icons/5042-XP-iCandy2.zip
    123k /tmp/icons/test/hallo.txt
    456k /tmp/icons/test/hallo1.doc


    ----

    how can i calculate the size of the directories so the parent
    directory has the size of all childdirs?


    this is what i want:

    /tmp/icons=2095
    /tmo/icons/test=579

    the problem is i do not know how many dirs i am reading from the file.
    this is what i have so far. this will only get the size from the files
    within a directory but it does not add childdirectories to the total
    size of the parent.


    ---
    sub main {


    my $args = $_[0];

    my %size;

    if ( $whichFile eq "AGELIST" ) {
    open DATA, "</tmp/mpf$$/AGELIST.mpf"
    or die "Couldn't open all: $!\n";
    }
    else {
    open DATA, "</tmp/mpf$$/FILTEREDLIST.mpf"
    or die "Couldn't open all: $!\n";
    }

    my @files = <DATA>;

    for (@files) {
    chomp;
    my ( $size, $path ) = split;

    my $bytes = toBytes $size;
    my $dir = dirname $path;
    $size{$dir} += $bytes;
    }

    for (@files) {
    chomp;
    my ( $size, $path ) = split;

    next unless exists $size{$path};

    my $dir = dirname $path;
    my $bytes = toBytes $size;
    $size{$dir} -= $bytes;
    }

    #den berechneten Wert fuer die Ausgabe zurueckgeben (mit Klammern oder
    ohne)
    if ( toUnit( $size{$args} ) eq "" ) {
    return ( toUnit( $size{$args} ) );
    }
    else {
    return "[" . ( toUnit( $size{$args} ) ) . "]";
    }
    } # Ende von main
    ---

    ---
    sub toBytes {
    my $size = shift;

    if ( $size =~ tr/k$//d ) {
    $size *= 1024;
    }
    elsif ( $size =~ tr/M$//d ) {
    $size *= 1024 * 1024;
    }

    $size;
    } #Ende von toBytes

    sub toUnit {

    my $size = shift;

    if ( $size > 1024 * 1000 ) {

    $size = sprintf "%.1f M", $size / ( 1024 * 1024 );

    }
    elsif ( $size > 1024 ) {

    $size = sprintf "%.1f k", $size / 1024;

    }

    $size;
    } #Ende von toUnit

    ---


    i am calling the main method like that:


    main(/var/log)
     
    Math55, Jul 29, 2003
    #1
    1. Advertising

  2. Garry Short <> wrote:

    > while (<FILE>) {
    > shift;



    What is the shift() meant to accomplish?

    It looks superfluous (or even damaging) to me...


    > my ($size, $dir) = split;



    That will fail for pathes that contain spaces.


    > my @f = split /\//, $dir;



    That will fail on systems that use some other directory separator.


    use File::Basename;

    will fail in neither case.



    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Jul 29, 2003
    #2
    1. Advertising

  3. Math55

    Garry Short Guest

    Math55 wrote:

    > hi, i have the follwoing list.
    >
    >
    > ----
    >
    > 528k /tmp/icons/4599-OS-X-GamePak.tar.gz
    > 244k /tmp/icons/4780-OS-Logos.tar.gz
    > 744k /tmp/icons/5042-XP-iCandy2.zip
    > 123k /tmp/icons/test/hallo.txt
    > 456k /tmp/icons/test/hallo1.doc
    >
    >
    > ----
    >

    <SNIP>
    Okay, assuming the above file is in list.txt:

    my %hash;
    open FILE, "list.txt" or die "Can't open list.txt: $!\n";
    while (<FILE>) {
    shift;
    my ($size, $dir) = split;
    my @f = split /\//, $dir;
    while (@f) {
    $hash{$dir} += $size;
    pop(@f);
    $dir = join "/", @f;
    }
    }
    close FILE;
    foreach my $level (sort keys %hash) {
    print "$level = $hash{$level}\n";
    }

    I think that works ...
    Sorry I've rewritten it rather than fix your code - too much to read :)

    HTH,

    Garry
     
    Garry Short, Jul 29, 2003
    #3
  4. Math55

    Garry Short Guest

    Tad McClellan wrote:

    > Garry Short <> wrote:
    >
    >> while (<FILE>) {
    >> shift;

    > What is the shift() meant to accomplish?

    Umm ... good question ...

    >> my ($size, $dir) = split;

    > That will fail for pathes that contain spaces.

    I just picked the seperator out of the code he supplied

    >> my @f = split /\//, $dir;

    > That will fail on systems that use some other directory separator.

    Again, pulled out of the info the OP supplied ...

    > use File::Basename;
    > will fail in neither case.
    >



    Hmmmm .... that's the second time you've had to correct me today ... not
    having a good day, am I? :)

    Cheers,

    Garry
     
    Garry Short, Jul 29, 2003
    #4
  5. Tad McClellan <> wrote:

    >> my ($size, $dir) = split;

    >
    > That will fail for pathes that contain spaces.
    >
    >> my @f = split /\//, $dir;

    >
    > That will fail on systems that use some other directory separator.
    >
    > use File::Basename;
    >
    > will fail in neither case.



    How about this little demo program? It still depends on '/' being
    the root directory, though.

    I think it does what the OP wants, but more eyeballs might see
    something I missed.



    use strict;
    use warnings;
    use File::Basename;

    my %dir_total;
    while (<DATA>) {
    chomp;
    next unless /^(\S+)\s+(\S+.*)$/; # skip invalid input
    my ($size, $filename) = ($1, $2);
    my $bytes = toBytes($size);
    my $path = dirname $filename;
    while ($path) {
    $dir_total{$path} += $bytes;
    last if $path eq '/'; # stop when we reach the root
    $path = dirname $path;
    }
    }

    use Data::Dumper;
    print Dumper \%dir_total; # I didn't want to write an output routine

    sub toBytes {
    my $size = shift;
    if ( $size =~ /^(\d+)(.?)$/ ) {
    return $1 if $2 eq '';
    return $1*1024 if $2 eq 'k';
    return $1*1024*1024 if $2 eq 'M';
    return $1*1024*1024*1024 if $2 eq 'G';
    }
    warn "Unexpected input to toBytes: '$size'";
    return 0; # may not be what you want
    }

    __DATA__
    528k /tmp/icons/4599-OS-X-GamePak.tar.gz
    244k /tmp/icons/4780-OS-Logos.tar.gz
    744k /tmp/icons/5042-XP-iCandy2.zip
    123k /tmp/icons/test/hallo.txt
    456k /tmp/icons/test/hallo1.doc
     
    David K. Wall, Jul 29, 2003
    #5
  6. Math55

    Math55 Guest

    "David K. Wall" <> wrote in message news:<Xns93C797E47CC47dkwwashere@216.168.3.30>...
    > Tad McClellan <> wrote:
    >
    > >> my ($size, $dir) = split;

    > >
    > > That will fail for pathes that contain spaces.
    > >
    > >> my @f = split /\//, $dir;

    > >
    > > That will fail on systems that use some other directory separator.
    > >
    > > use File::Basename;
    > >
    > > will fail in neither case.

    >
    >
    > How about this little demo program? It still depends on '/' being
    > the root directory, though.
    >
    > I think it does what the OP wants, but more eyeballs might see
    > something I missed.
    >
    >
    >
    > use strict;
    > use warnings;
    > use File::Basename;
    >
    > my %dir_total;
    > while (<DATA>) {
    > chomp;
    > next unless /^(\S+)\s+(\S+.*)$/; # skip invalid input
    > my ($size, $filename) = ($1, $2);
    > my $bytes = toBytes($size);
    > my $path = dirname $filename;
    > while ($path) {
    > $dir_total{$path} += $bytes;
    > last if $path eq '/'; # stop when we reach the root
    > $path = dirname $path;
    > }
    > }
    >
    > use Data::Dumper;
    > print Dumper \%dir_total; # I didn't want to write an output routine
    >
    > sub toBytes {
    > my $size = shift;
    > if ( $size =~ /^(\d+)(.?)$/ ) {
    > return $1 if $2 eq '';
    > return $1*1024 if $2 eq 'k';
    > return $1*1024*1024 if $2 eq 'M';
    > return $1*1024*1024*1024 if $2 eq 'G';
    > }
    > warn "Unexpected input to toBytes: '$size'";
    > return 0; # may not be what you want
    > }
    >
    > __DATA__
    > 528k /tmp/icons/4599-OS-X-GamePak.tar.gz
    > 244k /tmp/icons/4780-OS-Logos.tar.gz
    > 744k /tmp/icons/5042-XP-iCandy2.zip
    > 123k /tmp/icons/test/hallo.txt
    > 456k /tmp/icons/test/hallo1.doc




    hi, i will try that tomorrow. here is a program that uses the 3
    methods. justopen a new filehandle to a file that looks like i said!

    ---
    #! /usr/local/bin/perl

    use strict;
    use warnings;

    use File::Basename;

    sub to_bytes {
    my $size = shift;

    if ($size =~ s/k$//) {
    $size *= 1024;
    }
    elsif ($size =~ s/M$//) {
    $size *= 1024 * 1024;
    }

    $size;
    }

    sub to_unit {
    my $size = shift;

    if ($size > 1024 * 1024) {
    $size = sprintf "%.1fM", $size / (1024*1024);
    }
    elsif ($size > 1024) {
    $size = sprintf "%.1fk", $size / 1024;
    }

    $size;
    }

    ## main
    my %size;
    my @files = <DATA>;

    for (@files) {
    chomp;
    my($size,$path) = split;

    my $bytes = to_bytes $size;
    my $dir = dirname $path;
    $size{$dir} += $bytes;
    }

    # pass two: zap subdirs from parents' totals
    for (@files) {
    chomp;
    my($size,$path) = split;

    next unless exists $size{$path};

    my $dir = dirname $path;
    my $bytes = to_bytes $size;
    $size{$dir} -= $bytes;
    }

    for (sort { $a cmp $b } keys %size) {
    print "$_ - ", to_unit($size{$_}), "\n";
    }

    __DATA__
    32k /var/log/XFree86.0.log
    76k /var/log/auth.log
    116k /var/log/auth.log.0
    8.0k /var/log/auth.log.1.gz
    228k /var/log/kdm.log
    20k /var/log/kern.log
    1.2M /var/log/kern.log.0
    12k /var/log/kern.log.1.gz
    2.8M /var/log/ksymoops
    228k /var/log/ksymoops/20030628062520.ksyms
    4.0k /var/log/ksymoops/20030628062520.modules
    228k /var/log/ksymoops/20030629062502.ksyms
    4.0k /var/log/ksymoops/20030629062502.modules
    12k /var/log/ksymoops/20030630.log
    228k /var/log/ksymoops/20030630062525.ksyms
    4.0k /var/log/ksymoops/20030630062525.modules
    12k /var/log/ksymoops/20030701.log
    228k /var/log/ksymoops/20030701062504.ksyms

    ---

    how must i change the code so it works with this implementation?
    thanks :)
     
    Math55, Jul 29, 2003
    #6
  7. Math55 <> wrote:

    > how must i change the code so it works with this implementation?
    > thanks :)


    Pay me lots of money and I'll do it for you. Otherwise, spend a few
    minutes reading the code. It's not exactly complicated, and besides it
    may not even do what you want. If you understand Greg Bacon's code[1]
    then what I posted should present no problem.

    (I didn't notice the thread from several weeks ago about this problem
    until after I had posted.)

    [1] Message-ID: <>
     
    David K. Wall, Jul 29, 2003
    #7
  8. Math55

    Math55 Guest

    "David K. Wall" <> wrote in message news:<Xns93C7B723587DAdkwwashere@216.168.3.30>...
    > Math55 <> wrote:
    >
    > > how must i change the code so it works with this implementation?
    > > thanks :)

    >
    > Pay me lots of money and I'll do it for you. Otherwise, spend a few
    > minutes reading the code. It's not exactly complicated, and besides it
    > may not even do what you want. If you understand Greg Bacon's code[1]
    > then what I posted should present no problem.
    >
    > (I didn't notice the thread from several weeks ago about this problem
    > until after I had posted.)
    >
    > [1] Message-ID: <>



    ok, i think i got it now. there is only one problem left. here is the cdoe:


    ---
    use strict;
    use warnings;
    use File::Basename;

    my $path1 = '/tmp/FILTEREDLIST.mpf';

    print calc("/tmp/FSHOME/icons");


    sub calc{

    my $args = $_[0];

    open FH, "< $path1" or die $!;

    my %dir_total;
    my $path;
    while (<FH>) {
    chomp;
    next unless /^(\S+)\s+(\S+.*)$/; # skip invalid input
    my ($size, $filename) = ($1, $2);
    my $bytes = toBytes($size);

    $path = dirname $filename;
    while ($path) {
    $dir_total{$path} += $bytes;
    last if $path eq '/'; # stop when we reach the root
    $path = dirname $path;
    }
    }

    #use Data::Dumper;/FSHOME
    #print Dumper \%dir_total; # I didn't want to write an output routine
    #for my $file ( sort keys %dir_total ){
    return ($dir_total{$args});
    #return (%dir_total);

    #print "total: $dir_total{$args}\n";
    #}
    }


    sub toBytes {
    my $size = shift;
    if ( $size =~ /^(\d+)(.?)$/ ) {
    return $1 if $2 eq '';
    return $1*1024 if $2 eq 'k';
    return $1*1024*1024 if $2 eq 'M';
    return $1*1024*1024*1024 if $2 eq 'G';
    }
    warn "Unexpected input to toBytes: '$size'";
    return 0; # may not be what you want
    }

    ---

    FILTEREDLIST.mpf looks like that:

    152k /tmp/FSHOME/icons
    8.0k /tmp/FSHOME/icons/X.gif
    4.0k /tmp/FSHOME/icons/agent.gif
    4.0k /tmp/FSHOME/icons/cdimage.gif
    4.0k /tmp/FSHOME/icons/cdwriter_unmount.gif
    4.0k /tmp/FSHOME/icons/connect_creating.gif
    8.0k /tmp/FSHOME/icons/debian.gif
    4.0k /tmp/FSHOME/icons/exit.gif
    4.0k /tmp/FSHOME/icons/filefind.gif
    4.0k /tmp/FSHOME/icons/fileopen.gif
    4.0k /tmp/FSHOME/icons/folder_yellow_open.gif
    4.0k /tmp/FSHOME/icons/gohome.gif
    4.0k /tmp/FSHOME/icons/help.gif
    4.0k /tmp/FSHOME/icons/idea.gif
    4.0k /tmp/FSHOME/icons/info.gif
    4.0k /tmp/FSHOME/icons/kedit.gif
    4.0k /tmp/FSHOME/icons/koncd.gif
    4.0k /tmp/FSHOME/icons/kscreensaver.gif
    4.0k /tmp/FSHOME/icons/ktip.gif
    4.0k /tmp/FSHOME/icons/mandrake.gif
    4.0k /tmp/FSHOME/icons/personal.gif
    4.0k /tmp/FSHOME/icons/pfaster.gif
    4.0k /tmp/FSHOME/icons/ping.gif
    4.0k /tmp/FSHOME/icons/redfaction.gif
    8.0k /tmp/FSHOME/icons/redhat.gif
    4.0k /tmp/FSHOME/icons/stop.gif
    8.0k /tmp/FSHOME/icons/suse.gif
    4.0k /tmp/FSHOME/icons/tar.gif
    4.0k /tmp/FSHOME/icons/tgz.gif
    8.0k /tmp/FSHOME/icons/tux.gif
    4.0k /tmp/FSHOME/icons/txt.gif
    4.0k /tmp/FSHOME/icons/view_text.gif
    4.0k /tmp/FSHOME/icons/zip.gif

    when i call the method like i did in the code above i get 0 as return value, why?

    THANKS FOR YOUR EFFORTS:)
     
    Math55, Jul 30, 2003
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Marlon
    Replies:
    1
    Views:
    2,219
    Tom Kaminski [MVP]
    Sep 10, 2004
  2. hupjack
    Replies:
    4
    Views:
    778
    hupjack
    May 5, 2004
  3. TJS
    Replies:
    9
    Views:
    16,204
    gosborne
    Sep 7, 2010
  4. rick
    Replies:
    4
    Views:
    159
  5. bin_P19 P
    Replies:
    0
    Views:
    172
    bin_P19 P
    Apr 21, 2004
Loading...

Share This Page