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

Hello Monks,

Need your help again. I am using grep function to select certain file names in an array using file mask. When I use the a scalar variable as the regular expression pattern in the grep function, I get wrong result. A hard coded pattern returns the right result. Please see the code below.

use strict; my $folder="."; my $file_mask="\.txt"; my $file; opendir(DIR, "$folder"); my @files =grep(/$file_mask$/,readdir(DIR)); closedir(DIR); foreach $file (@files) { print "$file\n"; # Finds a file called 1txt (WHY) } opendir(DIR, "$folder"); @files =grep(/\.txt$/,readdir(DIR)); closedir(DIR); foreach $file (@files) { print "$file\n"; # Does not find the file called 1txt (As expected) }

I would greatly appreciate your input regarding this anomaly.

Ash

Replies are listed 'Best First'.
Re: Question: File name pattern match using Grep function
by BrowserUk (Patriarch) on May 05, 2009 at 02:07 UTC
    # Finds a file called 1txt (WHY)

    Because "\.txt" becomes just '.txt', which when it is reinterpolated here:

    my @files =grep(/$file_mask$/,readdir(DIR));

    Is taken to mean 'any char' followed by 'txt$'. To avoid the problem, use

    my @files =grep(/\Q$file_mask\E$/,readdir(DIR));

    To prevent characters within $file_mask being treated as meta characters.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Question: File name pattern match using Grep function
by Anonymous Monk on May 05, 2009 at 02:02 UTC
    /.txt/ and /\.txt/ are two different patterns, only the first one will match ltxt.
    my @files = glob "$folder/*$file_mask";
Re: Question: File name pattern match using Grep function
by hexcoder (Curate) on May 05, 2009 at 14:27 UTC
    alternatively use
    my $file_mask='\.txt';
    to avoid interpretation of the '\'. Please note the different quotes.
Re: Question: File name pattern match using Grep function
by johngg (Canon) on May 05, 2009 at 21:38 UTC

    Yet another way to avoid the interpolation problem would be to pre-compile your pattern into a regular expression using qr. You might also consider tightening up your grep condition in case somebody is silly enough to name a directory "confusing.txt" and if you want to exclude symbolic links if on *nix.

    ... my $file_mask = qr{\.txt$}; ... my @files = grep { m{$file_mask} and -f and not -l } readdir DIR; ...

    I hope this is of interest.

    Cheers,

    JohnGG

Re: Question: File name pattern match using Grep function
by senthilkumar.k (Initiate) on May 06, 2009 at 16:53 UTC
    #!/usr/bin/perl use strict; use warnings; my @filename =(); while (my $File = <*>) { if (! -f "$File") { # Ignore directories and such next; } elsif ($File =~ m/\.txt$/o) { push (@filename,$File); } } foreach my $val (@filename) { print $val,"\n"; }