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

Hello everyone,

I am in the middle of developing a perl script and since being new to perl I am giving it my best shot, I have gotten a start and need a tiny help to do the following. I need to get a particular file from a directory after matching a unique keyword in that file. So for example a dir has 10 files, and only one file has the keyword APPLES in it, I need to store the name of that file in my variable $filename.

Any ideas people

Thanks for the help in advance

Replies are listed 'Best First'.
Re: Get Filename using perl
by Corion (Patriarch) on Sep 09, 2004 at 06:57 UTC

    There is also the incredibly handy and usefull File::Find::Rule module:

    use strict; use File::Find::Rule; my $commonField = 'Perl'; my $responseDir = '.'; my @files = File::Find::Rule->grep($commonField)->file->in($responseDi +r); print "I found '$searched_word' in $_" for @files;
Re: Get Filename using perl
by ikegami (Patriarch) on Sep 09, 2004 at 02:30 UTC

    From the prompt: grep -l keyword *

    Lazy perl way: $filename = `grep -l keyword *`

    or

    # Exits as soon as a match is found. # only reads a line in at a time, not the entire file. sub find_file { my ($dir_name, $keyword) = @_; my $file_name; my $file_path; my $dh = DirHandle->new($dir_name) or die("Can't read directory: $!.\n"); while (defined($file_name = $dh->read())) { $file_path = "$dir_name/$file_name"; next if ($file_name eq '.'); next if ($file_name eq '..'); next unless (-f $file_path); my $fh = FileHandle->new($file_path, 'r') or warn("Can't read file $file_name: $!.\n"); while (defined($_ = $fh->getline())) { return $file_name if (index($_, $keyword) != -1); } } return undef; }
Re: Get Filename using perl
by Zaxo (Archbishop) on Sep 09, 2004 at 01:24 UTC

    What do you want to happen if there is more than one file with the keyword? The (non-perl) grep utility is the usual way to solve this problem.

    Guessing that you don't have system grep, you should generate a list of all filenames of interest with glob. Then open each and loop through the contents trying to match the keyword with the match operator, m/APPLES/. If a match is found, note the filename and go on to the next. That can be done in a way that generates an array of qualified files, using push.

    After Compline,
    Zaxo

      I know for a fact that there will be only one UNIQUE KEYWORD, which will not be repeated in any other file
        As they say, assumption is the mother of all foul-ups. The computer does exactly what it's told. At some point, someone will tell it to place the keyword in more than one file. At that point, things will break if you haven't decided to deal with it gracefully.

        thor

        Feel the white light, the light within
        Be your own disciple, fan the sparks of will
        For all of us waiting, your kingdom will come

Re: Get Filename using perl
by Rhys (Pilgrim) on Sep 09, 2004 at 02:23 UTC
    The Perl grep returns the matching contents from the file, not the file name, so your code should be more like:

    opendir (DIR, "$responseDir") or die "could not open $responseDir :$!\ +n"; foreach $file ( readdir(DIR) ) { open THISFILE, "$responseDir/$file"; my @newFile = grep { /$commonField/ } <THISFILE>; if ( @newFile ) { # If there were any contents, this is our file. $matchedfile = $file; close THISFILE; last; } close THISFILE; } closedir(DIR); print "Matched file $matchedfile.\n";

    I tested a slight variation of this. You'll definitely want to re-test this, but I think it works.

    --J

Re: Get Filename using perl
by Anonymous Monk on Sep 09, 2004 at 01:16 UTC
    BTW.. this is what i am trying and it's not working
    opendir (DIR, "$responseDir") or die "could not open $responseDir :$!\ +n"; my @newFile = grep { $commonField -f $responseDir/$_ } readdir(DIR); closedir(DIR);

      grep and glob are often very useful, for example:

      my $dir = '.'; my $match = 'perl'; my @files = grep { -f } glob ( "$dir/*" ); for my $file(@files) { open my $fh, $file or next; print "Found match in $file\n" if grep{ /\Q$match\E/ }<$fh>; }

      cheers

      tachyon

      readdir returns the names of files, not their contents, so you're actually searching for files whose name matchs your keyword.