Calculate directorysize from a list?

M

Math55

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)
 
T

Tad McClellan

Garry Short said:
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.
 
G

Garry Short

Math55 said:
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
 
G

Garry Short

Tad said:
What is the shift() meant to accomplish?
Umm ... good question ...
That will fail for pathes that contain spaces.
I just picked the seperator out of the code he supplied
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
 
D

David K. Wall

Tad McClellan said:
That will fail for pathes that contain spaces.


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
 
M

Math55

David K. Wall said:
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
 
D

David K. Wall

Math55 said:
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: <[email protected]>
 
M

Math55

David K. Wall said:
Math55 said:
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: <[email protected]>


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:)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,778
Messages
2,569,605
Members
45,238
Latest member
Top CryptoPodcasts

Latest Threads

Top