views:

174

answers:

5

Updated According to comments:

I have outlog.txt file which contains multiple filenames, e.g: 2345_535_Dell&HP_3PAR_DEAL.txt, similarly there are many filename but not the actual folder where the files are located and so in code am appending filenames to folderpath to get actual file location. Now,I want to get disk usage of all the files present in outlog.txt and also total disk usage of all files present in outlog.txt.

I have tried two approaches perl -s and my ($size) = split(' ', du `"$folderpath/$_"`) but both approaches are giving me different values and also when I am using du than am getting some numeric value but it does not give me unit, is there a way I can get human readable without using -h option as it is not working on my system ?

Background Information

My goal is to get the size of a file, and currently I am using perl -s to get filesize. I have also tried du and am getting different values for the size of the same file. I am not able to understand how this works.

Q: Why do du and perl -s give different values for size? How do they internally work? Which of the two different values is the more accurate one? Also, I'm not sure why du -h filename gives me an illegal expression error:

bash-2.03$ du -h test.txt
/usr/bin/du: illegal option -- h
usage: du [-a][-d][-k][-r][-o|-s][-L] [file ...]

Code:

my $folderpath = 'the_path';
open my $IN, '<', 'path/to/infile';
my $total;
while (<$IN>) {
    chomp;
    my $size = -s "$folderpath/$_";
    print "$_ => $size\n";
    $total += $size;
}
print "Total => $total\n";

Courtesy: RickF

Update:

Q: How can I get the disk usage value instead of file size for each file present, meaning how can I get du value for each files rather than perl -s values for file ?

OS Information uname :SunOS uname -v :Generic_117350-39

Updated Code: According to brain's approach but still du value prints as zero only and not the actual value, any suggestions ?

Update: If I use my ($size) = split(' ', du "$folderpath/$_"); than I am getting du value but it gives me some number, how can I get it into human readable without using -h option ?

 #!/usr/bin/perl
 use strict;
 use warnings;

my $folderpath = '/Project/upload';
open my $IN, '<', 'outlog.txt';
my $total;
while (<$IN>) {
    chomp;
    #my( $block_size, $blocks ) = ( stat( "$_" ) )[11,12];
    #my $du_size = $block_size * $blocks;
    my ($size) = split(' ', `du "$folderpath/$_"); 
    #my $size = -s "$folderpath/$_";
    print "$_ => $size\n";
    $total += $size;
}
print "Total => $total\n";
+3  A: 

du stands for "Disk Used", and reports the physical size of the file on disk. If the file is sparse, this may be much smaller than its logical size, which is what -s reports. Both are "accurate", they're just measuring different things.

The error message indicates that the version of du installed on your machine doesn't understand the -h option.

cjm
I found this response confusing in light of [Wooble's](http://stackoverflow.com/questions/3773017/why-do-du-and-perls-s-give-different-values-for-the-file-size/3773074#3773074), if `du` is showing *blocks* (512 *bytes*), that the number is smaller because one *block* can fit 512 *bytes*, not because the file is *sparse*? Unless I'm missing something.
Evan Carroll
I see now [sparse file](http://en.wikipedia.org/wiki/Sparse_file)
Evan Carroll
@Evan Carroll, `du` is capable of reporting sizes in different units. I'm not sure what the default unit is for SunOS. Try `man du`.
cjm
+6  A: 

du reports actual disk usage, Perl's -s reports the size of the file. So, if a file is four bytes long it will have a size of four bytes, but disk usage of four kilobytes (depending on how your filesystem is setup).

You will also see a difference in the sizes of sparse files. Sparse files take up less space than they claim to have in them.

Chas. Owens
+3  A: 

By default, du displays the number of blocks used by a file (where each block is 512 bytes on most systems), while perl's -s displays bytes.

As to why your copy of du doesn't have a -h option, you don't tell us what operating system you're using; it appears to include a horribly outdated version of the program.

UPDATE: to get disk usage in perl, you can use the Filesys::DiskUsage module.

Wooble
@Wooble - I do not have `.pm` installed for `Filesys::DiskUsage`
Rachel
@Rachel, `cpanp install Filesys::DiskUsage`
Evan Carroll
@Evan: Is that the command, actually am still in my early days with `Perl` so not very familiar of doing perl in smart ways `:0`
Rachel
@Rachel Yep, for 5.10+ use `cpanp`, that command will do it all for you.
Evan Carroll
@Rachel: You should also `cpanp install autodie`, and `use autodie;` (you're not checking `$!` in your code)
Evan Carroll
`bash: cpanp: command not found`
Rachel
@Evan: Am getting error message as `bash: cpanp: command not found`
Rachel
Rachel: That probably means you're on a perl that is a few years old (older than 5.10 anyway)., you can use the older `cpan Filesys::DiskUsage` instead.
Evan Carroll
+1  A: 

If you want du to give the same results as Perl's -s, try du -b. If your du supports it, this gives the "apparent size", which is different from disk usage, as others have stated.

But to do this you'll have to update your du.

Update for OP's updated code: Make sure that the file exists within your current working directory. You may have to prepend the directory to make sure that Perl is finding the file.

It may also clarify things if you get away from using $_ everywhere:

while( my $line = <$IN> ) {
  chomp $line;
  my( $block_size, $blocks ) = ( stat( $line ) )[11,12];
  ...
}

This way you're safe from unintentional changes to $_.

CanSpice
+1 for `my $line =<$IN>` suggestion
Rachel
Evan, the `defined` isn't necessary. When we hit the end of the file, `<$IN>` returns `undef`, which gets assigned to `$line`. The return value of the assignment is thus also `undef`, which gets translated to false, and the `while()` loop exits. This is why I've rolled back your edit that added the `defined` check.
CanSpice
@CanSpice it is necessary, if you ever get a file called 0, or " " you'll stop execution (not that it really happens too much, but you're leaving your result dependent on the perl truth table, rather than eof())
Evan Carroll
@Evan: please see http://stackoverflow.com/q/3773917/40468, and read http://perldoc.perl.org/perlop.html#I/O-Operators.
Ether
@Ether: You're right, but the Perl docs are misleading. They say, "If **and only if** the input symbol is the only thing inside the conditional of a while statement" -- but later contradict the "and only if" part by showing that `while (my $line = <STDIN>)` also behaves the same way. Leaving us wondering about exactly which circumstances this DWIMmery will be performed in.
j_random_hacker
@j_random: thanks; that's something we can get clarified in the next release of the perldocs.
Ether
@j_random: I just noticed that you (and then I) left this comment on the wrong question. :)
Ether
@Ether: Yep, and now I know it's wrong too... :-P
j_random_hacker
+2  A: 

Everyone else has already noted that the file size and disk use are different beasts. However, if you want to get the same answer as du, you can use the stat to get the block size and the number of blocks that a file uses:

From Perl, to get the disk used (blocks unavailable for use for other files):

 # to match du
 my( $block_size, $blocks ) = ( stat( $file ) )[11,12];
 my $du_size = $block_size * $blocks;
brian d foy
@brian: I have updated code accordingly and I tried to ran the code and it does not prints `du value`, am I missing out something here ?
Rachel
@Rachel The value `du` prints if given no other arguments is the number of blocks, try just printing `$blocks`.
Chas. Owens
@Chas. Owens: I am getting `Global symbol "$blocks" requires explicit package name at FileSizeSumDuTest.pl line 15. Execution of FileSizeSumDuTest.pl aborted due to compilation errors`,I just replaced `$du_size` by `$blocks`
Rachel
@Rachel: that means you haven't declared `$blocks` properly. You have to declare variables with `my`.
CanSpice
Well, your code doesn't compile, and I don't know what your input is. That makes it hard to tell what you are actually doing.
brian d foy
Rachel
Comments aren't a good place for this sort of information. Edit your question to add sample input, etc. My suggestion is to start your questions with what you are trying to accomplish, not how you think you should do it.
brian d foy
I have updated questions according to comments, hope now it is much more clear as to what I am trying to accomplish.
Rachel