Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

File::Find preprocess

by pvaldes (Chaplain)
on Jan 08, 2018 at 16:20 UTC ( [id://1206910] : perlquestion . print w/replies, xml ) Need Help??

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

Lets suppose that we have a dir A with two subdirs B and C each one having two files on it named: a1, a2, b1, b2, and, c1, c2. I'm using File::Find to traverse the entire tree

My goal is to explore the preprocess and postprocess options in the function find from this module. My dumb function should print "hi" each time I enter in a dir, "bye" each time I finish with this directory and "file! " for each file present in the dir:

#!/usr/bin/perl -w use strict; use File::Find; my $dir = '.'; find({preprocess => \&before, wanted => \&when, postprocess => \&after +}, $dir); sub before { print "hi "; exit 0; } sub after { print "bye "; } sub when { print "file! "; return; }

I expect having printed three "hi", three "bye" and six "file!" in this order: hi file! file! bye (repeated three times);

I obtain instead just "file! hi", and the same if I change "exit 0;" by "exit 1;" Can somebody please explain why?

Replies are listed 'Best First'.
Re: File::Find preprocess
by tybalt89 (Monsignor) on Jan 08, 2018 at 17:13 UTC
    #!/usr/bin/perl # use strict; use warnings; use File::Find; $| = 1; my $dir = 'A'; find({preprocess => \&before, wanted => \&when, postprocess => \&after +}, $dir); sub before { print "hi "; sort @_ } sub after { print "bye " } sub when { print "file! $File::Find::name " }


    file! A hi file! A/a1 file! A/a2 file! A/B hi file! A/B/b1 file! A/B/b +2 bye file! A/C hi file! A/C/c1 file! A/C/c2 bye bye

    Looks about right :)

Re: File::Find preprocess
by karlgoethebier (Abbot) on Jan 08, 2018 at 16:26 UTC


    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: File::Find preprocess
by pvaldes (Chaplain) on Jan 08, 2018 at 16:33 UTC

    Shouldn't exit, just close the function "before"?.

    If I remove all "return" and "exit" the program process the parent dir, but not the subdirs (prints: file! hi file! bye)

      No. The problem here is that you aren't completely reading documentation.

      exit exits an entire process stack (ie. your program). return does leave the subroutine.

      This, combined with the preprocess misconception is what's causing your issues.

        Hum, I see. I was expecting an equivalent to the "previously" condition in a common-lisp loop structure. A chunk of code that happens only once before the main body of the function starts iterating. I understand that if I need to do something within each subdirectory (check if something happens inside each subdir first), I would need then to traverse the tree two times using two different find functions. One for directories only, and a second for all files. Right? can't be done in one take?

      And more strange, If I change the function wanted like this:

      sub when { print $File::Find::name," "; }

      I obtain: ". hi ./1 bye", even if the file "1" does not exist

      Updated: I mean file::find, not find::file

        Per the documentation, preprocess receives a list (of entries in the current directory), and is expected to return a list (of entries). The purpose for this functionality is to provide you the ability to prune, filter, reorganize etc the list of entries as you sweep over them before the wanted function is called (it receives the list returned from preprocess).

        The most basic test you can do is just immediately return the list the begin function receives:

        sub begin { my @entries = @_; print "begin\n"; return @entries; }

        The reason you're getting "1", is because that's what a successful print statement returns, and in Perl, if you don't have an explicit return(), the result of the last expression evaluated is returned (in your case, the result of the print, meaning "1").

        my $x = print "hi\n"; print "$x\n"; __END__ hi 1