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

In my code I call a find routine called find_me based on what the user enters which can be "/" or /\/\w+/. Instead of having two identical blocks of code with the only difference being $File::Find::prune = #; can't I just pass this $File::Find::prune = 1; or $File::Find::prune = 0 to my single find routine based on their entry?

use strict; use warnings; use File::Find ; use File::Find::Closures qw(find_by_min_size) ; <snip> chomp (my $fs = <>) ; if ( $fs =~ m|\x2f{1}?|g ) { ##-- if "/" is matched --# $File::Find::prune = 0; find_me; } elsif ( $fs !~ m|\/\w+| ) { $File::Find::prune = 1; find_me; find_me { my @directory = ($fs) ; use constant MAX_SIZE => (25*1024*1024) ; use constant DIVISOR => (1024) ; my ( $wanted, $list ) = find_by_min_size ( MAX_SIZE ) ; File::Find::find ( { wanted => $wanted, }, @directory ) ; <snip> } <snip>
thank you

Replies are listed 'Best First'.
Re: file::find question
by hipowls (Curate) on Jan 04, 2008 at 23:57 UTC

    I'm not sure what you trying to match, you say the user can enter either the literal string "/" or the regular expression /\/w+/ but then test for neither.

    m|\x2f{1}?| is just an obscure way of sayingm|/| which is not the same thing as $fs eq "/". The g modifier seems unnecessary. The next test checks for input that doesn't match /\/w+/.

    I will guess that you don't want to prune if the directory path has a '/' and do otherwise.

    find_me( $fs, $fs =~ m|/| ); sub find_me { my @directory = shift; # play nicely with others local $File::Find::prune = shift; <snip> }
      your guess is right, however saying m|/| matches / and /var.

      /etc/skel$ perl -le '$foo=qq(/); print "YES" if $foo =~ m|/|;' YES /etc/skel$ perl -le '$foo=qq(/var); print "YES" if $foo =~ m|/|;' YES

      And yet I need my code to match "/" independently and "/var" independently.

      print "enter text\n"; chomp(my $fs = <>); if ( $fs !~ m|/\w+| ) { ##-- only look for / --## print "YES\t$fs\nfirst test\n"; } elsif ( $fs =~ m|/\w+| ) { ##-- only look for /words --## print "YES\t$fs\nsecond test\n"; } /etc/skel$ /etc/skel$ perl test1 enter text /var YES /var second test /etc/skel$ perl test1 enter text / YES / first test

      thus I use the code, but can you explain how I will use something similar to find_me( $fs, $fs =~ m|/| );

      if ( $fs !~ m|/\w+| ) { ##-- only look for / --## find_me($File::Find::prune = 1); ##-- false, do not prune past / - +-## find_me; } elsif ( $fs =~ m|/\w+| ) { ##-- only look for /words --## find_me($File::Find::prune = 0); ## true, prune dir tree --## } sub find_me { my @directory = ($fs) ; use constant MAX_SIZE => (25*1024*1024) ; use constant DIVISOR => (1024) ; my ( $wanted, $list ) = find_by_min_size ( MAX_SIZE ) ; File::Find::find ( { wanted => $wanted, }, @directory ) ; my ( @sorted_large_files, @large_files ) ; @large_files = $list->() ; <snip> }

        There are three possible actions

      • do not process
      • process and prune
      • process and do not prune
      • It seems to me that your cases are

      • / root directory, do not prune
      • /var /usr/local an absolute path where the top level directory has a name beginning with a-z A-Z or _, prune
      • every thing else e.g. .ssh /.kde tmp ../etc /+share, ignore
      • if ( $fs eq '/' ) { # only if the root directory my_find( $fs, 0 ); } elsif ( $fs =~ m|^/\w+| ) { # matches /var my_find( $fs, 1 ); } else { # everything else which we ignore # /.ssh # tmp # working/data # /-etc } sub find_me { my @directory = shift; # play nicely with others local $File::Find::prune = shift; <snip> }

        If these are not the cases that you want to match I strongly suggest that you think clearly about what you are trying to match. Are relative paths allowed? How about the tmp directory in your current working directory (no / in the path)? Is there a need to restrict directory names to beginning with word characters?

        Note that I pass parameters to find_me() rather rely on global variables, find_me() can now be used from elsewhere in the program. Also I localize $File::Find::prune so that changes to File::Find within find_me() don't leak out into the rest of your program. If you don't do that you will have to remember to explicit reset $File::Find::prune before you use any Find::File function elsewhere (or spend hours debugging;).

        Maybe I'm failing to see a difficult thing here, but couldn't you just do:
        # Sticking with pattern matching find_me( $fs, $fs =~ m|^/$| ); # Simpler find_me( $fs, $fs eq '/' ); # Simpler Still $File::Find::prune = $fs ne '/'; find_me;