[26679] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 8786 Volume: 10

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Thu Dec 22 11:05:30 2005

Date: Thu, 22 Dec 2005 08:05:05 -0800 (PST)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)

Perl-Users Digest           Thu, 22 Dec 2005     Volume: 10 Number: 8786

Today's topics:
        Dynamic directory handles? <whoever@whereever.com>
    Re: Dynamic directory handles? <1usa@llenroc.ude.invalid>
    Re: Dynamic directory handles? (Anno Siegel)
    Re: Dynamic directory handles? <tadmc@augustmail.com>
    Re: FAQ 4.22 How do I expand function calls in a string (Anno Siegel)
    Re: FAQ 4.22 How do I expand function calls in a string <sdn.girths00869@zoemail.net>
        Help needed with AppConfig <itfred@cdw.com>
    Re: Help needed with AppConfig <1usa@llenroc.ude.invalid>
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Thu, 22 Dec 2005 12:19:31 -0000
From: "IanW" <whoever@whereever.com>
Subject: Dynamic directory handles?
Message-Id: <doe5kj$ms$1@blackmamba.itd.rl.ac.uk>

I have a chunk of code that counts files.dirs and size for a directory tree. 
It goes like this:

================
#use strict;

my $basedir = "j:/files/sw-test";
my $fcount = 0;
my $fsize = 0;
my $dcount = 0;
dircount();

sub dircount {
        my($cdir) = shift;
        $cdir .= "/" if $cdir ne "";
        my $dh = "DH" . length($cdir);
        opendir($dh,"$basedir/$cdir");
        while(my $fl = readdir($dh)){
                next if $fl =~ /^\.{1,2}$/;
                if(-d "$basedir/$cdir$fl"){
                        $dcount++;
                        dircount("$cdir$fl");
                }
                else{
                        $fcount++;
                        $fsize += -s "$basedir/$cdir$fl";
                }
        }
        close($dh);
}

print "$fcount files and $dcount directories totalling $fsize bytes in 
size";
================

If I "use strict" it says "Can't use string ("DH0") as a symbol ref while 
"strict refs" in use at D:\test.pl line 14". What's the best way to get 
round this, since I need a dynamic dir handle for the routine to work 
properly.

Thanks
Ian




------------------------------

Date: Thu, 22 Dec 2005 12:51:17 GMT
From: "A. Sinan Unur" <1usa@llenroc.ude.invalid>
Subject: Re: Dynamic directory handles?
Message-Id: <Xns97344FEAA98EDasu1cornelledu@127.0.0.1>

"IanW" <whoever@whereever.com> wrote in
news:doe5kj$ms$1@blackmamba.itd.rl.ac.uk: 

> I have a chunk of code that counts files.dirs 

First off, you are better off doing this using the File::Find module 
rather than using recursion. If this is not a learning exercise, then I 
would also urge you to look at File::Find::Rule to simplify matters when 
processing items one by one.

> ================
> #use strict;
> 
> my $basedir = "j:/files/sw-test";

The program should check @ARGV for an argument, and supply a reasonable 
default if one is not present.

> my $fcount = 0;
> my $fsize = 0;
> my $dcount = 0;

These are values that should be returned by your sub. You might want to 
check for calling context in the sub and supply an appropriate scalar 
value.

> dircount();
> 
> sub dircount {
>         my($cdir) = shift;
>         $cdir .= "/" if $cdir ne "";
>         my $dh = "DH" . length($cdir);

Using lexical dirhandles, this should not be necessary.

>         opendir($dh,"$basedir/$cdir");

You should *always* check if calls to open/opendir succeeded.

>         while(my $fl = readdir($dh)){
>                 next if $fl =~ /^\.{1,2}$/;
>                 if(-d "$basedir/$cdir$fl"){
>                         $dcount++;
>                         dircount("$cdir$fl");
>                 }

I do prefer using File::Spec for path manipulation.

> If I "use strict" it says "Can't use string ("DH0") as a symbol ref
> while "strict refs" in use at D:\test.pl line 14". What's the best way
> to get round this, since I need a dynamic dir handle for the routine
> to work properly.

Here is a revised version of your code. I cannot vouch for its accuracy, 
since there seems to be discrepancy between the output of this script 
and that of du on my system (probably because the space taken by zero-
length files is not taken to account). As always, corrections welcome:

#!/usr/bin/perl

use strict;
use warnings;

use File::Spec::Functions qw(canonpath catfile);

my $basedir = canonpath($ARGV[0] || '.');
my ($fcount, $dcount, $fsize) = dircount($basedir);


printf("%d files and %d directories totalling %d bytes in size\n",
   $fcount, $dcount, $fsize);

sub dircount {
   my ($cdir) = @_;
   my ($fcount, $dcount, $fsize) = (0, 0, 0);
   my $path = catfile($basedir, $cdir);
   opendir my $dh, $path or die "Cannot open directory '$path': $!";
   while (my $fl = readdir($dh)){
      next if $fl eq '.' or $fl eq '..';
      if(-d (my $d = catfile($path, $fl))){
         $dcount++;
         my ($fc, $dc, $fs) = dircount($d);
         $fcount += $fc;
         $dcount += $dc;
         $fsize  += $fs;
      } else {
         $fcount++;
         $fsize += -s $d;
      }
   }
   close($dh);
   return ($fcount, $dcount, $fsize);
}





-- 
A. Sinan Unur <1usa@llenroc.ude.invalid>
(reverse each component and remove .invalid for email address)

comp.lang.perl.misc guidelines on the WWW:
http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html



------------------------------

Date: 22 Dec 2005 12:55:11 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: Dynamic directory handles?
Message-Id: <doe7nf$7eg$2@mamenchi.zrz.TU-Berlin.DE>

IanW <whoever@whereever.com> wrote in comp.lang.perl.misc:
> I have a chunk of code that counts files.dirs and size for a directory tree. 
> It goes like this:
> 
> ================
> #use strict;
> 
> my $basedir = "j:/files/sw-test";
> my $fcount = 0;
> my $fsize = 0;
> my $dcount = 0;
> dircount();
> 
> sub dircount {
>         my($cdir) = shift;
>         $cdir .= "/" if $cdir ne "";
>         my $dh = "DH" . length($cdir);
>         opendir($dh,"$basedir/$cdir");
>         while(my $fl = readdir($dh)){
>                 next if $fl =~ /^\.{1,2}$/;
>                 if(-d "$basedir/$cdir$fl"){
>                         $dcount++;
>                         dircount("$cdir$fl");
>                 }
>                 else{
>                         $fcount++;
>                         $fsize += -s "$basedir/$cdir$fl";
>                 }
>         }
>         close($dh);
> }
> 
> print "$fcount files and $dcount directories totalling $fsize bytes in 
> size";
> ================
> 
> If I "use strict" it says "Can't use string ("DH0") as a symbol ref while 
> "strict refs" in use at D:\test.pl line 14". What's the best way to get 
> round this, since I need a dynamic dir handle for the routine to work 
> properly.

Just leave $dh undefined instead of setting it to a string value.
opendir() will then create an anonymous directory handle.  So change

    my $dh = "DH" . length($cdir);

to

    my $dh;

Also, you call dircount() without an argument.  Presumably you wanted
to say

    dircount( $basedir);

A better solution would be to use the standard module File::Find:

    use File::Find;

    sub dircount {
        my $cdir = shift;
        find sub {
            if ( -d ) {
                ++ $dcount;
            } else {
                ++ $fcount;
                $fsize += -s;
            }
        }, $cdir;
    }

Anno
-- 
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article.  Click on 
"show options" at the top of the article, then click on the 
"Reply" at the bottom of the article headers.


------------------------------

Date: Thu, 22 Dec 2005 08:04:49 -0600
From: Tad McClellan <tadmc@augustmail.com>
Subject: Re: Dynamic directory handles?
Message-Id: <slrndqlck1.71n.tadmc@magna.augustmail.com>

IanW <whoever@whereever.com> wrote:

> I have a chunk of code that counts files.dirs and size for a directory tree. 


You have a whole bunch of problems, some big, some small.

I'll mention the lesser ones in comments about your code below,
but the 3 big ones are:

1) You should always enable warnings (and strict) when
   developing Perl code.

2) You get a dynamic dirhandle the same way you get a dynamic
   filehandle, so:

   perldoc -q filehandle

     How can I make a filehandle local to a subroutine?  How do I pass file-
     handles between subroutines?  How do I make an array of filehandles?

3) There is an already-invented (and tested) wheel for doing 
   recursive directory searching, the File::Find module.

You can read the module's docs with:

   perldoc File::Find


>================
> #use strict;


You lose all of the benefits of that statement when you comment it out!


> my $basedir = "j:/files/sw-test";
> my $fcount = 0;
> my $fsize = 0;
> my $dcount = 0;
> dircount();
> 
> sub dircount {
>         my($cdir) = shift;


$cdir will be undef for the top-level call.


>         $cdir .= "/" if $cdir ne "";


You have all of the path components separated already, so I'd
paste the dir separator in myself on each usage instead of
burying one inside of a variable's value.


>         my $dh = "DH" . length($cdir);
>         opendir($dh,"$basedir/$cdir");


You get a dynamic dirhandle when the variable is undef.

Your variable is not undef, so there is no dynamic dirhandle...


You should always check the return value to see if you actually
got what you asked for:

   opendir($dh,"$basedir/$cdir") or die "could not open '$basedir/$cdir' $!";


>         while(my $fl = readdir($dh)){
>                 next if $fl =~ /^\.{1,2}$/;
>                 if(-d "$basedir/$cdir$fl"){
>                         $dcount++;
>                         dircount("$cdir$fl");


If $fl is a symlink to a "higher" directory, then your
code will go into an infinite loop here.



Applying the minimum changes to fix (IMO) your code, I get:

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

my $basedir = '/home/tadmc/temp';
my $fcount = 0;
my $fsize = 0;
my $dcount = 0;
dircount();

sub dircount {
        my($cdir) = shift || '';
        opendir(my $dh,"$basedir/$cdir") or die "could not open dir $!";
        while(my $fl = readdir($dh)){
                next if $fl =~ /^\.{1,2}$/;
                if(-d "$basedir/$cdir/$fl"){
                        $dcount++;
                        dircount("$cdir/$fl");
                }
                else{
                        $fcount++;
                        $fsize += -s "$basedir/$cdir/$fl";
                }
        }
        close($dh);
}

print "$fcount files and $dcount directories totalling $fsize bytes in size\n";
------------------------



Recasting it to use the tried-and-true module, I get:

------------------------
#!/usr/bin/perl
use warnings;
use strict;
use File::Find;

my $basedir = '/home/tadmc/temp';
my $fcount = 0;
my $fsize = 0;
my $dcount = 0;
find( \&dircount, $basedir );

sub dircount {
   return if $_ eq '.' or $_ eq '..';
   $dcount++ if -d;
   return unless -f;   # only care about plain files at this point
   $fcount++;
   $fsize += -s;
}

print "$fcount files and $dcount directories totalling $fsize bytes in size\n";
------------------------


-- 
    Tad McClellan                          SGML consulting
    tadmc@augustmail.com                   Perl programming
    Fort Worth, Texas


------------------------------

Date: 22 Dec 2005 11:00:16 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: FAQ 4.22 How do I expand function calls in a string?
Message-Id: <doe100$7eg$1@mamenchi.zrz.TU-Berlin.DE>

PerlFAQ Server  <comdog@pair.com> wrote in comp.lang.perl.misc:
> This message is one of several periodic postings to comp.lang.perl.misc
> intended to make it easier for perl programmers to find answers to
> common questions. The core of this message represents an excerpt
> from the documentation provided with Perl.
> 
> --------------------------------------------------------------------
> 
> 4.22: How do I expand function calls in a string?
> 
>     (contributed by brian d foy)
> 
>     This is documented in perlref, and although it's not the easiest thing
>     to read, it does work. In each of these examples, we call the function
>     inside the braces of used to dereference a reference. If we have a more
>     than one return value, we can construct and dereference an anonymous
>     array. In this case, we call the function in list context.

Small textual correction:

     This is documented in perlref, and although it's not the easiest thing
     to read, it does work. In each of these examples, we call the function
     inside the braces used to dereference a reference. If we have more than
     one return value, we can construct and dereference an anonymous array.
     In this case, we call the function in list context.


Anno
-- 
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article.  Click on 
"show options" at the top of the article, then click on the 
"Reply" at the bottom of the article headers.


------------------------------

Date: Thu, 22 Dec 2005 06:03:59 -0600
From: "Eric J. Roode" <sdn.girths00869@zoemail.net>
Subject: Re: FAQ 4.22 How do I expand function calls in a string?
Message-Id: <Xns9734483751634sdn.comcast@216.196.97.136>

PerlFAQ Server <comdog@pair.com> wrote in
news:doc1s4$lr4$1@reader1.panix.com: 

> This message is one of several periodic postings to
> comp.lang.perl.misc intended to make it easier for perl programmers to
> find answers to common questions. The core of this message represents
> an excerpt from the documentation provided with Perl.
> 
> --------------------------------------------------------------------
> 
> 4.22: How do I expand function calls in a string?

Do you think it's worthwhile to mention the Interpolation module?

    use Interpolation E => 'eval';
    print "The time values are $E{localtime()}.\n";

-- 
Eric
`$=`;$_=\%!;($_)=/(.)/;$==++$|;($.,$/,$,,$\,$",$;,$^,$#,$~,$*,$:,@%)=(
$!=~/(.)(.).(.)(.)(.)(.)..(.)(.)(.)..(.)......(.)/,$"),$=++;$.++;$.++;
$_++;$_++;($_,$\,$,)=($~.$"."$;$/$%[$?]$_$\$,$:$%[$?]",$"&$~,$#,);$,++
;$,++;$^|=$";`$_$\$,$/$:$;$~$*$%[$?]$.$~$*${#}$%[$?]$;$\$"$^$~$*.>&$=`


------------------------------

Date: Wed, 21 Dec 2005 23:00:07 -0500
From: Fred <itfred@cdw.com>
Subject: Help needed with AppConfig
Message-Id: <pan.2005.12.22.04.00.06.719591@cdw.com>

If I run the code snippet below using the AppConfig
module, I receive the error:

   user: no such variable
   Use of uninitialized value in print at ./appconfig.pl line 22.

I've included the app.cfg configuration file that I'm reading
with AppConfig.  I read the docs, but don't see what I'm
doing wrong.  Any ideas?

-Thanks


appconfig.pl
#!/usr/bin/perl -w

use strict;

use AppConfig qw(:expand);

my $cfgfile = '/home/fred/app.cfg';
my $config = AppConfig->new($cfgfile);
print $config->user();  



/home/fred/app.cfg:

user = fred
home = /home/fred


------------------------------

Date: Thu, 22 Dec 2005 04:22:14 GMT
From: "A. Sinan Unur" <1usa@llenroc.ude.invalid>
Subject: Re: Help needed with AppConfig
Message-Id: <Xns9733EDBF2CFEasu1cornelledu@127.0.0.1>

Fred <itfred@cdw.com> wrote in news:pan.2005.12.22.04.00.06.719591
@cdw.com:

> If I run the code snippet below using the AppConfig
> module, I receive the error:
> 
>    user: no such variable
>    Use of uninitialized value in print at ./appconfig.pl line 22.
> 
> I've included the app.cfg configuration file that I'm reading
> with AppConfig.  I read the docs, but don't see what I'm
> doing wrong.  Any ideas?
>

I have never used AppConfig, but it looks like you need to specify the 
variables you expect to read from the config file in the call to new:

<URL:http://search.cpan.org/src/ABW/AppConfig-1.56/t/file.t>

Sinan

-- 
A. Sinan Unur <1usa@llenroc.ude.invalid>
(reverse each component and remove .invalid for email address)

comp.lang.perl.misc guidelines on the WWW:
http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html



------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

#The Perl-Users Digest is a retransmission of the USENET newsgroup
#comp.lang.perl.misc.  For subscription or unsubscription requests, send
#the single line:
#
#	subscribe perl-users
#or:
#	unsubscribe perl-users
#
#to almanac@ruby.oce.orst.edu.  

NOTE: due to the current flood of worm email banging on ruby, the smtp
server on ruby has been shut off until further notice. 

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

#To request back copies (available for a week or so), send your request
#to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
#where x is the volume number and y is the issue number.

#For other requests pertaining to the digest, send mail to
#perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
#sending perl questions to the -request address, I don't have time to
#answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V10 Issue 8786
***************************************


home help back first fref pref prev next nref lref last post