steph_bow has asked for the wisdom of the Perl Monks concerning the following question:

Hello, Dear Monks,

I have make a script to go into some directories and perform some process here. But I think it is too complicated and I would like to use File::Find but I can't see how to apply it to my case ? Could you give me some advice ?

Here is the script (the path for the directories has been tested).

#! /usr/bin/perl -w use strict; use File::Find; BEGIN { open(STDERR, ">stderr.log") or die "Failed to open log file"; } sub process{ # to be completed } my @REGS = (LAR30, TYE68, SOK96); my $reg; my $date; my $week; # $date and $week are determined for each $reg via a hash foreach $reg(@REGS){ chdir("../ALL_WEEKS/semaine_${week}") or die; chdir("semaine_${week}_TACOT/day_${date}") or die; chdir("r_${date}") or die; chdir("${reg}") or die ; # I do not know how to apply find::file here &process{$dir}; } close STDERR;

update : simplification of the script

Replies are listed 'Best First'.
Re: how to use file::Find ?
by poolpi (Hermit) on Apr 17, 2008 at 11:43 UTC

    First if you want to find the week number :
    See DateTime

    #!/usr/bin/perl -w use strict; use DateTime; my $date = q{20060911}; my $year = substr( $date, 0, 4 ); my $month = substr( $date, 4, 2 ); my $day = substr( $date, 6, 2 ); print DateTime->new( year => $year, month => $month, day => $day )->we +ek_number;

    hth,
    PooLpi

    'Ebry haffa hoe hab im tik a bush'. Jamaican proverb

      Hello poolpi,

      Thanks a lot for your help

      For the moment, I do not have the right to install this new module. But I will have the right in a few days. Could you tell me in which directory I should install it ? Because all the .pm files are in several directories and I don't know in which directory the file should be.

Re: how to use file::Find ?
by apl (Monsignor) on Apr 17, 2008 at 11:46 UTC
    I regret I can't answer your immediate question. I would like to suggest, though, that you
    • remove the @ALL_WEEK_DAYS definitions (they're not relevant to the question at hand)
    • turn the code that determines $week into a subroutine
    • remove commented out code
    The smallest example you can provide is mosty likely to get a response from someone who can help you.
Re: how to use file::Find ?
by starbolin (Hermit) on Apr 17, 2008 at 17:43 UTC

    The first argument of find() is a reference to a subroutine. This is where you tell find what you want done with the filenames it finds. Find will pass the names it finds into $_ . Say you wanted to print a list of all the files below your current directory:

    find sub{print $_,"\n"}, "./"

    The second parameter to find() takes an array of directories. If you only have one directory, as above, that is fine. Remember that perl passes parameters in a flat list so a single scalar will pass the same as an array of one element.

    You can try this from the command line to get familiar with the concept:

    %perl -MFile::Find -e 'find sub{print $_,"\n"}, "./"'

    Of course find() really shines when iterating over a list of directories: find sub ( do-something }, @directories Note: This can return a lot of files as find() works recursively down through all the sub directories.

    Find does not return the found files so this:  @array = find(); Doesn't work. You have to store the files passed to you yourself if you want to keep them. Like this: find sub { push @filelist, $_ }, @directories;

    Of course if you subroutine is more complicated then it can be written separately and a reference to it passed to find().

    sub my_Sub{ do-something-with-$_ . . } find \&my_Sub, @directories;


    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
Re: how to use file::Find ?
by oko1 (Deacon) on Apr 18, 2008 at 04:17 UTC

    Hi again, steph_bow - I guess since I got you started down this road, I might as well keep you going. :) By the way, I note that you're still using a 'BEGIN' block in your code without any specific reason; you should probably read up on these special blocks (the section is called 'BEGIN, UNITCHECK, CHECK, INIT and END') to find out what they're for - and you shouldn't use them gratuitously.

    File::Find is a nicely-documented module; you should read up on it by typing 'perldoc File::Find' (the exact case is important) at your command line. The short version, however, is that the 'find' function takes a sub reference as its first argument and a list of directories as the second - as starbolin mentioned. From what I see in your code, you mostly need to learn how to permute lists of directories - something like the following:

    (pseudocode)
    (A B, C) x (D, E, F) = (A/D, A/E, A/F, B/D, B/E, B/F, C/D, C/E, C/F)
    

    In the example that I gave you the last time, I cheated a bit and used brace expansion in the glob statement - i.e., I used the shell to do the work (*bad, bad me...* :) This time, however, I'll do it "the right way", by using 'map':

    use warnings; use strict; ### Make up some numbers :) my ($week, $date) = qw/36 250/; my @regs = qw(LAR30 TYE68 SOK96); ### Interpolate the directory lists @dirs = map { "../ALL_WEEKS/semaine_$week/semaine_${week}_TACOT/day_$date/r_$dat +e/$_" } @regs; ### Now that we have our list of directories, process them find(\&process, @dirs); sub process { ### Do stuff to the files returned by File::Find (represented by ' +$_') print "File name: $_\n"; }
    
    -- 
    Human history becomes more and more a race between education and catastrophe. -- HG Wells