-2

Topic. I'm trying to get the size of a directory without using the Find module and without using the du command. Here's how I'm currently approaching it but it doesn't seem like it's returning the correct size. It's returning 418836 bytes but when I run du -s the directory size is 141508.

my $size = dir_size('wp-content');

sub dir_size {  
  my $dir  = shift;
  my $size = 0;

  opendir(DIR,"$dir");

  foreach my $node (grep(!/^\.\.?/,readdir())) {
     stat($node);
     if(-f $node) {
       $size += -s $node;
     } elsif(-d $node) {
       $size += dir_size("$dir/$node");
     } 
  }
  closedir(DIR);

  return $size;
}

hoping someone can point out what im doing wrong.

SelfTaught
  • 482
  • 6
  • 16
  • 3
    By the "Find module," I assume you mean [`File::Find`](http://perldoc.perl.org/File/Find.html). Any particular reason you don't want to use it? It's a core module. – ThisSuitIsBlackNot Feb 05 '15 at 17:06
  • `stat` doesn't give you a particularly good measure, but it'll do the trick. But be very careful when trying to reinvent the wheel of a core module. `File::Find` is quite mature, and copes with symlinks, assorted fruity filenames, and a variety of things that will trap the unwary. Although, are you actually using the results of your `stat`? – Sobrique Feb 05 '15 at 17:10
  • 1
    Is this a homework question perhaps? We will answer homework questions, but they require a different sort of answer that will help you learn instead of just getting you to your goal. Please explain why you want to avoid using `File::Find`? I have wriitten a working solution using it in my answer to [your previous question](http://stackoverflow.com/q/28341724). If you explain your reasons to us it will aid us enormously in helping you towards an answer. What you have written in your question is effectively what `File::Find` does, but it gets it right. – Borodin Feb 05 '15 at 17:13
  • Disregard this post please. I thought the environment I was running my perl script in didn't have the File module but checked after @ThisSuitIsBlackNot pointed out it's a core module and it's there. I apologize. Thanks for your replies though ! – SelfTaught Feb 05 '15 at 17:17
  • 1
    If you had only answered our questions, or even tried running the program in my solution, you would have found that your search was unnecessary. If you ask questions on Stack Overflow, then please be guided by the people here instead of deciding that you know better and ignoring us. – Borodin Feb 05 '15 at 17:26
  • possible duplicate of [How to find folder size in Perl using File::stat module?](http://stackoverflow.com/questions/28341724/how-to-find-folder-size-in-perl-using-filestat-module) – Sobrique Feb 05 '15 at 17:32
  • @borodin. I apologize. However, that is not my post and this is the first time I've asked this. I thought I had to avoid using File::find because i need to use this script in two similar environments. One is a VPS server running CentOS and the other is a shared server also running centos. There are modules installed on the shared server which are not installed on the VPS. I wanted to make sure this works in both. I ran instmodsh -l on both and on the VPS i did not see File but on the shared I did. I assumed (which I should not have done) that it wasn't installed. – SelfTaught Feb 05 '15 at 17:55
  • @Dillan: Thank you, I also apologise. The content is so similar -- even down to the request to avoid `File::Find` -- that I jumped to the conclusion that the preceding question was also from you, without comparing the authors. My frustration with the previous poster overflowed onto you and I'm sorry. Your post and comments here are very reasonable. – Borodin Feb 05 '15 at 18:08
  • @Dillan I'm not positive, but even on a shared host I think you should be able to [install modules in your home directory](http://stackoverflow.com/questions/3735836/how-can-i-install-perl-modules-without-root-privileges). You're really limiting yourself if you only use core modules. – ThisSuitIsBlackNot Feb 05 '15 at 18:16
  • Installing a module isn't an option because the accounts I'm working with are not mine. – SelfTaught Feb 05 '15 at 18:28
  • @Dillan: A Perl module is often just a Perl source file. All that is necessary is to copy that file alongside your own source file and everything will work. – Borodin Feb 05 '15 at 18:44
  • The `File::Find` is a ***standard*** Perl module. Heck, it's been a standard Perl module since Perl 3.x came out back in the early 1990s. `File::Find` should be on any Perl 5.x installation you run into. What version of Perl are you running on each system? Look at the official [Perl Documentation](http://perldoc.perl.org) page and see what modules are included with each version. Don't ever be afraid of using a STANDARD Perl module. Consider them part of base Perl. – David W. Feb 05 '15 at 20:43

1 Answers1

1

Here's a very basic solution that avoids the File::Find module. It ignores symlinks as well as the pseudo-directories . and .., which are probably the source of your own code's problems. It also optimises the -f, -d, and -s tests by calling stat just once and using the pseudo-filename _ thereafter.

The read_size function returns a simple number, but commas are added before every three digits of the printed string so that it is more readable for larger values.

use strict;
use warnings;
use 5.010;    # For `say` and regex `\K` construct

my $s = dir_size('wp-content');
1 while $s =~ s/ \d+ \K (\d{3}) /,$1/x;
say $s;

sub dir_size {  

    my ($dir) = @_;

    my $size = 0;

    opendir my ($dh), $dir or die $!;

    while (my $node = readdir $dh) {
        next if $node =~ /\A\.\.?\z/;

        my $fullname = "$dir/$node";
        stat $fullname;

        if ( -f _ ) {
            $size += -s _;
        }
        elsif ( -d _ ) {
            $size += dir_size($fullname);
        }
    }

    $size;
}
Borodin
  • 126,100
  • 9
  • 70
  • 144