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

I need a list of files for a specific directory- case-insensitive for the filename (not the dir). I can do it with a grep on a readdir, but from what I've read, Perl glob is a more natural way. I researched how to use glob. There is remarkably little information on perl glob, but after programming Perl myself since like 1995 and almost never using "glob", I think its little-understood and little-used. I found this suggestion:

use File::Glob qw( :globally :nocase); my @f = glob( "/someDir/someFile" );

I have a file in someDir named like someFile but not the same case, but this glob step returned an empty array.

The syntax seemed unusual, like the "use" statement replaced what are usually reserved-word options.

Advice on why this didn't work is appreciated. The example seemed wrong. It seemed like the glob() itself needs the switch, not the "use"?

Replies are listed 'Best First'.
Re: Can I get help with Perl glob for filtering a directory
by choroba (Cardinal) on Nov 03, 2023 at 17:11 UTC
    It seems File::Glob::glob only uses the :nocase when there are some wildcards to match, otherwise it tries to find the name case insensitive, and when it fails, it returns the pattern itself. Using glob without any wildcards is therefore useless. You can, though, make the filename into a pattern by just turning its last character into a character class:
    my @f = glob '/someDir/someFil[e]';

    My testing shows this behaviour is per node name, i.e. if you're not sure about the case of someDir, you need to change it to someDir, too.

    See Path::Tiny for much nicer interface to file structure.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Can I get help with Perl glob for filtering a directory
by Corion (Patriarch) on Nov 03, 2023 at 17:01 UTC

    Read File::Glob for finding out how you can find out what error glob() encounters:

    ... if (File::Glob::GLOB_ERROR()) { # an error occurred print "Glob error: $!"; }

    Also, are you sure that /someDir/someFile exists? What is the output of ls /someDir/someFile on the command line?

Re: Can I get help with Perl glob for filtering a directory
by tybalt89 (Monsignor) on Nov 03, 2023 at 21:05 UTC
    #!/usr/bin/perl use strict; # https://www.perlmonks.org/?node_id=11155355 use warnings; use Path::Tiny; system 'tree someDir'; print "\n"; my @f = path( 'someDir' )->children( qr/someFile*/i ); print "found $_\n" for @f;

    Outputs:

    someDir |-- SOMEFILE.tmp |-- someFile.txt `-- somefile.dat 1 directory, 3 files found someDir/somefile.dat found someDir/SOMEFILE.tmp found someDir/someFile.txt
Re: Can I get help with Perl glob for filtering a directory
by hippo (Archbishop) on Nov 03, 2023 at 17:16 UTC

    Works for me if I use a metacharacter so there's a dynamic pattern rather than a fixed string to match against. However, I generally prefer Path::Tiny for anything even slightly complex in this regard. Here are both approaches illustrated:

    #!/usr/bin/env perl use strict; use warnings; use autodie; use Test::More tests => 2; use File::Glob qw( :globally :nocase); use Path::Tiny; open my $foo, '>', '/tmp/MisterPerl'; print $foo "Yeah!\n"; close $foo; my (@f) = glob ('/tmp/misterper[l]'); is $f[0], '/tmp/MisterPerl', 'File found case-insensitively with File: +:Glob'; @f = path ('/tmp')->children (qr/^misterperl/i); is $f[0], '/tmp/MisterPerl', 'File found case-insensitively with Path: +:Tiny';

    Meta note: this node was apparently posted OK but not attached to the thread and then the content disappeared (see Re: Missing 'in reply to...' And 'in thread....'). I've restored the content now.

      Thanks all for the comments. I already read glob documentation,so that wasn't really helpful, and I don't recall anywhere that a wildcard was spcified there as required but perhaps.

      I'm trying to think of a SAFE way to wildcard the file and only get exact matches (except for case). I'm thinking maybe glob for

      myfilename*

      Then grep that list for files that match my original file length. Pretty tricky huh? I also read:

      https://metacpan.org/pod/Path%3A%3ATiny

      and ^F for "case" ; upper/lower didn't seem to be discussed at all.

      I'm thinking of just using something like the old reliable albiet fugly:

      my @f = grep /^\Q$fileName\E$/i,readdir D;

      This whole endeavor of asking this was to get more skilled with glob(). It seems strange to me that part of glob() functionality is to return a subset of the set of files in a dir. That's exactly what I want to do - just different than a partial filename? That's why glob() seemed like a more natural approach to this requirement.

      Larry said  Perl makes the difficult easy and the impossible possible. In this case, it seems it's making  Perl is making the easy, difficult! Just IMHO :)

      TY sirs and ladies..

        Grepping readdir seems pretty easy, aside from needing to opendir and check for errors, but the Path::Tiny ->children regex option is the easiest of all. Glob is easy if you want case-sensitive matches, which almost all Unix scripts would (the environment for which Perl was created). You also have the option of grepping glob, to save the opendir call:

        my @files= grep /\/\Q$fileName\E$/i, <$dirName/*>;

        but note that one important difference between glob and readdir is that glob will return the path portion as you specified it in the pattern.