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

wise Monks,

I am attempting to go through a single directory and preform and operation on each file in this directory and then place the files that have been edited in a subdirectory I need to create. By looking through this site I was introduced to File::Find and this looked to be exactly what I needed. But since I create a subdirectory in my script Find::File attempts to enter and search through the subdirectory, something I don't want. I tried to fix this by using "no_chdir => 0" but then the code doesn't preform any operations at all, also undesired. Any suggestions as how to fix this with File::Find or an alertnative would be much apperciated.

Thanks
SB

Replies are listed 'Best First'.
Re: File::Find problems
by ysth (Canon) on Sep 10, 2004 at 19:48 UTC
    Descending into subdirectories is pretty much what File::Find is for. If you don't need that, use glob or opendir/readdir and loop.
Re: File::Find problems
by bobf (Monsignor) on Sep 10, 2004 at 20:03 UTC

    I see ysth beat me to this one, but here is the code I was working on anyway. It uses the opendir/readdir/loop method:

    use strict; use warnings; use File::Spec; # for portable filename operations use File::Path; # to create the new subdirectory use File::Copy; # to move the edited file my $currentdir = '.'; my $newdir = File::Spec->catdir( $currentdir, 'newdir' ); # make the new subdirectory mkpath( $newdir ) or die "error creating $newdir"; # get all filenames in the current directory opendir( DIR, $currentdir ) or die "couldn't open $currentdir\n"; my @filenames = readdir DIR; closedir DIR; # get the program name so it's not moved if $currentdir eq '.' my ( undef, undef, $progname ) = File::Spec->splitpath( $0 ); foreach my $file (@filenames) { # add the full path to the filename my $pathfile = File::Spec->catfile( $currentdir, $file ); # skip if $file is a directory or this program if( -d $pathfile or $file eq $progname ) { next; } # process file here # move file to new subdir my $newpath = File::Spec->catfile( $newdir, $file ); move( $pathfile, $newpath ) or print "error moving $file"; }

    I'm sure more experienced Monks can come up with more elegant solutions, but this works on the tests I performed.

    HTH

    Update: Fixed code per parv's suggestion.

      my @filenames = readdir DIR; ... foreach my $file (@filenames) { if( -d $file or $file eq $0 ) ... }

      I doubt that the 2d part of the test will produce the desired result beacuse of ...

      readdir DIRHANDLE ... If you're planning to filetest the return values out of a "readdir", you'd better prepend the directory in question. Otherwise, because we didn't "chdir" there, it would have been testing the wrong file.
        Very good point. I set $currentdir to '.' to simplify the example, and forgot about it when I got to the loop. I'll update the code to include the full path of each $file. Thanks for pointing it out.
      Thanks all for the help and pointing me in the right dir(direction...not directory though in this case it is the same thing).
      SB
Re: File::Find problems
by runrig (Abbot) on Sep 10, 2004 at 19:51 UTC
    Set $File::Find::prune to true when it hits the subdirectory that you don't want to search. E.g.:
    $File::Find::prune = 1, return if -d and $_ = "some_subdirectory";
Re: File::Find problems
by YuckFoo (Abbot) on Sep 11, 2004 at 20:46 UTC
    Consider using File::Find::Rule. You specify the rules or conditions to meet. One rule is 'maxdepth' that limits how far down the tree to go:

    YuckFind

    #!/usr/bin/perl use strict; use File::Find::Rule; my @files = File::Find::Rule->file()->maxdepth(1)->in('/start/here') +; print "@files";
Re: File::Find problems
by McMahon (Chaplain) on Sep 10, 2004 at 19:57 UTC
    ysth is right, but here's a crude and wasteful solution:

    ... sub wanted { unless ($File::Find::dir =~ /subdir_name/ { #do something } }
Re: File::Find problems
by Plankton (Vicar) on Sep 10, 2004 at 19:46 UTC
    Why do you have to put the editted files in a subdirectory? Why not put the files in say ../newfiles? I am sure that there is a way to deal with it with Find::File, but I justed wondered if the subdirectoy requirement was necessary.

    Plankton: 1% Evil, 99% Hot Gas.
Re: File::Find problems
by tradez (Pilgrim) on Sep 10, 2004 at 20:53 UTC
    Well this might be OVERsimplifying things a bit, but hey, isn't that what perl is?
    my @files = `ls -l /dir/to/be/search`; foreach my $file (@files) { do whatever }
    Help any?


    Tradez
    "Never underestimate the predictability of stupidity"
    - Bullet Tooth Tony, Snatch (2001)

      A couple of notes about that:

      1. ls doesn't exist everywhere. I didn't see any mentioning in the OP about any particular OS, so it's not safe to assume that the user is on a Unix-alike or something with an ls command (though ppt definitely comes close).
      2. ls -l generates a lot of surplus output besides just the files. Furthermore, the output of ls -l is probably not standardised across different Unix systems.

        I agree that using "ls" in backticks is poor style and not to be encouraged. As for point 2, I wonder wether tradez actually intended to use the digit "-1" instead of the letter "-l" (so easy to get these mixed up) -- in any case, the digit "-1" option is of course unnecessary in this context, just as the letter "-l" option is unsuitable. Bad form all around.