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

Dear Monks,

I'm looking to very quickly write a program that will go through and search all files in a directory and its' subdirectories, search for a given word and then return all the files that contain this word. I can do this using convention scripting but I would like to use modules. Any suggestions or code that I can copy and paste would be most welcome.

Replies are listed 'Best First'.
Re: Easy way to search files?
by adrianh (Chancellor) on Jan 06, 2003 at 13:00 UTC

    Take a look at File::Find and File::Find::Rule. From the documentation of the latter:

    use File::Find::Rule; + # find all the subdirectories of a given directory + my @subdirs = File::Find::Rule->directory->in( $directory ); + + # find all the .pm files in @INC + my @files = File::Find::Rule->file() + ->name( '*.pm' ) + ->in( @INC );

    Once you have found the files you are interested, just open them and use m// (or whatever) to search for what you're interested in.

      I wonder why people choose the OO interface for File::Find::Rule.

      Personally, I prefer its functional interface. To demonstrate how clean it is, I'm rewriting the code you pasted from the documentation:

      use File::Find::Rule qw(find); my @subdirs = find 'directory', in => $directory; my @files = find 'file', name => '*.pm', in => \@INC;
      Would you choose the OO interface? Why?

      Another nice syntax for exactly the same is find file => (name => '*.pm', in => \@INC).

      - Yes, I reinvent wheels.
      - Spam: Visit eurotraQ.
      

        Would you choose the OO interface?

        Yes :-)

        Why?

        Because:

        • I find the OO style more readable.
        • Most of the code I write is OO. Using the OO API to File::Find::Rule saves me switching mental models.
        • Sometimes the intermediate objects are useful. You can use it to generate rules at runtime based on other conditions. This can be harder using the functional style.
      Once you have found the files you are interested, just open them and use m// (or whatever) to search for what you're interested in.

      Or use File::Find::Rule's grep predicate if you're interested in which files match (as the poster is) rather than exactly what they contain. :)

      The following exactly fulfills the poster's spec:

      my @files = File::Find::Rule ->file() ->grep(qr/\Q$word\E/) ->in(@directory);

      Makeshifts last the longest.

      On the topic of File::Find::Rule I'd like to mention that this module was featured in the Perl Advent Calender here (off-site link).

      -- Hofmator

Re: Easy way to search files?
by Zaxo (Archbishop) on Jan 06, 2003 at 13:15 UTC

    File::Find will handle recursive directory spanning.

    Here's a simple sub which takes a filepath and a string, returning true if the file contains the string. Slurp is used, so files should be smallish.

    sub contains { my ($file, $string) = @_; my $content; { local $/; open my $fh, '<', $file or die $!; $content = <$fh>; close $fh or die $!; } index( $content, $string) == -1 ? 0 : 1; }
    That should be fairly quick.

    Update: Any sub returns the value of its last expression unless an explicit return comes before. In sub contains, the trinary operator ?: tests whether index returned -1, and evaluates to zero if so, otherwise evaluates to 1. That could as well have been written     return not index( $content, $string) == -1 or     return index( $content, $string) != -1 where the return keyword is optional.

    After Compline,
    Zaxo

      That looks like what I need. I have a basic question though. I know how to return variables from a subroutine. I'm not, however, sure how this subroutine returns true. Or should I say that I am not sure how to return the fact that this subroutine returns true for each file. Can i just code to return a variable called $file_hit or something? That if indeed the file has been found to be true. I think that this post might be a bit confusing. I'm posting it anyway just in case people understand what is going through my mind.<\p>

        Hi ,

        The file content or pointer could be returned .
Re: Easy way to search files?
by Anonymous Monk on Jan 07, 2003 at 04:56 UTC
    Not to be anti-perl, but what you need is "grep". There are versions for win and obviously unix. This program is optimized to do exactly what you want. But, if your doing this to stimulate your perl brain cells, GO for it.
Re: Easy way to search files?
by Anonymous Monk on Jan 07, 2003 at 04:56 UTC
    The easiest way would be to use the find command.
    $ find . -exec grep -l TheWordIAmLookingFor {} \;
    This assumes a Unix OS or that you have cygwin installed
      This assumes a Unix OS or that you have cygwin installed

      No need to go that far-

      http://gnuwin32.sourceforge.net/
      Augh. One grep process per file? I don't think so. Assuming GNU versions of the utilitites involved, how about find -type f -print0 | xargs -0 grep TheWordIAmLookingFor

      Makeshifts last the longest.