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

I have a dedicated directory where users drop files. I have a config file that will take action upon the files in the directory based on the file name. Sometimes the users will drop a file name with extra characters in the file name. For example, file name "abc123" might be named "abc123.txt" or abc123_Jan2010" when they place the file tomorrow.

In my config file, I would like to enter fixed file names like "abc123" or filenames that need to be expanded, like "abc*". I want the fixed filename to match the exact file only, and the the expanded filename to match any file that fits the pattern. For example, "abc123" would match file name abc123 only, while "abc*" would match all the examples above.

I have tried using glob in my example below. My target directory has the following files:

> ls -1 /tmp/test
abc123
abc123.txt
abc123_Jan2010

Here is my code:
#!/opt/perl5/current/bin/perl chdir "/tmp/test"; $CONFIG = "abc123*"; @files = glob("$CONFIG"); foreach $file (@files) { print "$file \n"; }
Which provides the results I would expect:

> ./test.pl
abc123
abc123.txt
abc123_Jan2010

This works fine as long as the $CONFIG includes a wildcard. If I change the config to something like

$CONFIG = "xyz789";
the results are:

> ./test.pl
xyz789

Since the $CONFIG does not match a file in the directory, I would expect to get no results.

Is glob the wrong choice? Is there something that would expand the pattern match if a wildcard was present, and not expand if no wild card exists?

Thanks for any help you can provide!

Replies are listed 'Best First'.
Re: glob pattern matching
by graff (Chancellor) on Jan 13, 2010 at 23:35 UTC
    The glob function seems to work that way for me too. Here's a quick/easy work-around:
    #!/opt/perl5/current/bin/perl chdir "/tmp/test"; $CONFIG = "some_string_with_no_filename_wildcards"; @files = glob("$CONFIG"); foreach $file (@files) { next unless -e $file; print "$file \n"; }
    Or you could do it like this:
    foreach $file ( grep {-e} @files ) { print "$file\n"; }

    UPDATE: Actually, since the whole point of the "glob()" function (and the File::Glob module that implements it) is only to do file name expansions on strings that contain various kinds of regex-like wild-card matching directives, there is no point in using this function at all when a string does not contain any of these directives.

    So, if your config file uses just a simple set of wild-card-type things (like "*" and "?"), it might be better to only invoke glob() when one of those things is present in the string. Otherwise, just just the "-e" operator on the string:

    @files = ( $CONFIG =~ /[*?]/ ) ? glob( $CONFIG ) : ( -e $CONFIG ) ? ( +$CONFIG ) : ();
      Thanks for the suggestions!
Re: glob pattern matching
by ikegami (Patriarch) on Jan 14, 2010 at 01:48 UTC

    glob is a string generator. Other than ? and *, generating the strings neither requires nor warrants disk access.

    $ perl -le'print for glob "{a,b}{c,d}{e,f}"' ace acf ade adf bce bcf bde bdf

    You can always use -e if you want to check if the strings you generated matches file names.

    $ touch a{ce,df} $ perl -le'print for grep -e, glob "{a,b}{c,d}{e,f}"' ace adf

    Note how I used a glob to create files. If globs worked the way you wanted, I couldn't have done that.

Re: glob pattern matching
by DrHyde (Prior) on Jan 14, 2010 at 10:44 UTC
    glob() *expands* wildcards, but if there's no wildcard it leaves them alone, in just the same way as the shell does:
    $ echo $SHELL # yes, this is important! /bin/bash $ ls foo1 foo2 foo3 $ echo foo* foo1 foo2 foo3 $ echo foo foo
    There's a difference however, if you specify a wildcard that doesn't match anything:
    $ echo bar* bar* $ perl -e 'print glob("bar*")' $
    This is because glob() uses csh semantics:
    $ csh % ls foo1 foo2 foo3 % echo bar* echo: No match. % echo bar* echo: No match. % perl -e 'print glob("bar*")' %