in reply to Re^4: Help with $File:Find
in thread Help with $File:Find

Wow! This is a class of errors like a "UFO report". This can be hard to track down, but you already know that!

I will "think out loud" for a bit... I don't see any possible way that the wanted routine could actually be given an undef $_ value. It could be that there is something going wrong in the regex that causes an error message that is imprecise. I would look at quotemeta in the Perl docs. Using Perl variables in the regex can cause some weird things to happen, possibly related to some very unusual file name. I would use some form of quotemeta for the variables in your regex.

This is pretty short code and I would simplify it.

One issue is that I think your file test is not the best and as I mentioned before the nodirs() sub is not needed. There are things that are not directories, but which are also not actual files in the normal sense. Maybe some weird and unusual happens for these "strange files". I would eliminate nodirs() entirely and add a return unless -f $_; at the top of get_files(); That would eliminate the directories and also "files" which are not really files, like some kinds of links.

The use of my @array; in get_files() shows a fundamental misunderstanding of what the "wanted" routine gets and what it should do. @array will either be undefined or have at most one entry in it. Therefore your foreach loop is unnecessary. As general advice, I would keep the "wanted" subroutine as simple as possible, perhaps even declare my @array at a higher scope and just have get_files() just do the push? Find will actually cd (change directory) as it traverses the dir structure. Sometimes figuring out what Find was doing or doing some kind of error recovery can be problematic. I don't think that necessarily applies here. But my thinking would be that the code in the foreach loop doesn't needs to be in get_files() - mileage varies and I have no knowledge of your actual application.

One technique that can be used here is to install a signal handler for Warnings that would just apply to this section of code. When the WARNING happens, this code would intercept the WARNING message and execute some code that spews out what it knows about. This is one technique to capture info for "once every 2 week" sort of problems. This is complex enough that you should start a new SOPW question about how to do that. If I post code here like that, nobody with a similar problem will ever find it.

Replies are listed 'Best First'.
Re^6: Help with $File:Find
by roperl (Beadle) on Feb 20, 2018 at 18:22 UTC
    Thanks for your help on this one. Not sure why I thought the "wanted" routine would return more than one result. So I've removed the foreach(@array) and removed the nodirs() preprocessing
    find( { wanted => \&get_files }, "$BASEDIR/$dir" ); sub get_files { return unless ( -f $_ ); my $tmpfile = $File::Find::name if ( ($_) && ( (/^(?!\.).*\.($ +INTYPES)$/i) || ( (/^(?!\.).*\.($INTYPES)\.($ENGZTYPES)$/i) && !(/\.( +$OUTTYPES)\.($ENGZTYPES)$/i) ) ) ); if ( ( exists( $globalfiles{$tmpfile} ) ) && ( ( $globalfiles{ +$tmpfile} ne 'submitted' ) || ( $globalfiles{$tmpfile} ne 'working' ) + ) ) { return; } else { if ( -e $tmpfile ) { my $lckfile = getlckfile($tmpfile); push @tmparray, $tmpfile unless ( -e $lckfile ); } } }
      Actually there was a reason for nodirs(). I don't want to find recursively. I'm only looking for files in the specified directory, I'm not interested in anything in its sub directories if they exist
      find( { wanted => \&get_files, preprocess => \&nodirs }, "$BASEDIR/$di +r" ); sub nodirs { grep !-d, @_; }
      I'll have to add that part back in

        Hi,

        If you don't want to recurse , use maxdepth 1, not preprocess

        findrule is just about the easiest way to use File::Find

        $ findrule test test test/foo.txt test/test test/test/foooooo.txt $ findrule test -file test/foo.txt test/test/foooooo.txt $ findrule test -file -name "foo*txt" test/foo.txt test/test/foooooo.txt $ findrule test -file -name "foo*txt" -maxdepth 0 $ findrule test -file -name "foo*txt" -maxdepth 1 test/foo.txt $ findrule test -file -name "foo*txt" -maxdepth 2 test/foo.txt test/test/foooooo.txt

        setup/teardown

        perl -MPath::Tiny -le " path(q{test/test/foooooo.txt})->touchpath " perl -MPath::Tiny -le " path(q{test/foo.txt})->touchpath " perl -MPath::Tiny -le " path(q{test})->remove_tree "
        I am very skeptical that File::Find will do what you think it does.

        I figure that the preprocess routine will be run on each directory that is visited.
        This preprocess routine will not limit the subdirs that will be visited.
        This just organizes the order that files will be processed in current directory.

        There are other File::Find type of modules which limit the "depth". Is that what you want to do?

        On the other hand, if you don't want to follow into other directories, why do you even need File::Find?