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

I'm relatively new to perl, so I don't know if my problem was a bug, quirk, feature, or whatnot, but I thought I would post it here to see what more experienced monks might think.

So the point of the program is to search through a directory and pull data from text files of a certain name and then write that data to an excel file. I also want to take part of the directory for use as a worksheet name, which is where I was having my problem. The relevant code, set up to produce the error:

use warnings; use strict; use File::Find; my $directory = "\.\\v706_7-17"; # Set directory to search find(\&wanted, $directory); sub wanted { return unless -f; # Operate only on files, not directories my $curfile = $_; if ($curfile =~ m|list\$\$|i) { # If the file is a LIST$$ print "$directory\n"; # For debug purposes print "$File::Find::dir\n"; # For debug purposes $File::Find::dir =~ m|$directory\/(.*)|; # Variable way that +didn't work # $File::Find::dir =~ m|\.\\v706_7-17\/(.*)|; # Hardcoded way + that worked my $name = $1; $name =~ s|\/| |; # Replace "/" with " " for use in naming th +e worksheet ... #and on to the rest of the code.
I'm on a windows system, which is why I set the search directory to .\v706_7-17 instead of ./v706_7-17. The debug prints gave the expected results:
.\v706_7-17 .\v706_7-17/DSP-23/6DCL_Ada_Sci
But only the hardcoded version of the regex would find a match. Then, I tried changing the backslash to a forwardslash on the original search directory:
my $directory = "\.\/v706_7-17"; # Set directory to search
And I was greeted with success. The variable regex found a match and everything worked as it should. The debug printouts also gave the expected results:
./v706_7-17 ./v706_7-17/DSP-23/6DCL_Ada_Sci
So all in all, I found the whole thing a little strange that the debug printouts would match, but the regex wouldn't work as intended with the backslash.

Replies are listed 'Best First'.
Re: A Quirk in File::Find?
by ikegami (Patriarch) on Sep 23, 2009 at 21:15 UTC
    my $directory = "\.\\v706_7-17"; # Set directory to search m|$directory\/(.*)| # Variable way that didn't work

    So $directory contains the string .\v706_7-17. As a regex pattern, it matches a string that contains any character followed by a vertical whitespace (\v) followed by "706_7-17".

    You forgot to convert your literal text into a regex pattern. You can use quotemeta to do this, most easily via \Q\E:

    m|\Q$directory\E\/(.*)|

    Note that you probably want a ^ at the start of that pattern.

      Ah, I think I see what's going on. Basically, what's in $directory is being interpolated twice in the pattern match. The first interpolation is going from $directory to .\v706_7-17 and then it's being interpolated again, so it's looking for a vertical tab and then 706_7-17. And the forwardslash worked because it isn't a metacharacter. Thanks. That quotemeta will be useful in the future. I'd never heard of it before.

        and then it's being interpolated again,

        No. Then the string resulting from the interpolation is used as a regex pattern.

Re: A Quirk in File::Find?
by Corion (Patriarch) on Sep 23, 2009 at 21:16 UTC

    The cause is that the backslash is a special character in regular expressions. This is why you need to use quotemeta on $directory or use \Q...\E when interpolating $directory into your regular expression.

    Also, Perl on Windows does not have any problems with using a forward slash instead of a backslash as the directory separator.

    $File::Find::dir =~ m|\Q$directory\E\/(.*)|;