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

I'm trying to pull the filename of any file in a given directory with the .dat extension (I don't care which one).

I'm opening the directory, then using:

my @files = grep { /\.(?:dat)$/i } readdir DIR; closedir DIR; my $datfile = $files[0];
But it's not finding any files.

I'm really bad with regular expressions, so any assistance would be greatly appreciated.

Alternative methods are even more appreciated.

Replies are listed 'Best First'.
Re: Pulling a file with a given extension
by Roy Johnson (Monsignor) on Oct 18, 2005 at 16:48 UTC
    That's what file globs are for.
    my $datfile = (glob '*.dat')[0];

    Caution: Contents may have been coded under pressure.
      Be aware though that a glob might be slower than a loop:
      #!/usr/bin/perl use strict; use warnings; use Benchmark qw( cmpthese ); sub globber { return(( glob '*.xml')[0]); } sub opener { opendir my $dir, '.'; my $file; while (defined($file= readdir $dir)) { last if $file=~ /\.xml$/; } closedir $dir; return $file; } cmpthese(5000, { globber => \&globber, opener => \&opener, });
                Rate globber  opener
      globber  654/s      --    -76%
      opener  2688/s    311%      --
      

      s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
      +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

        That all depends ... on whether you manage to get the opener to work ;-)

        I'd rather go with a slow function that was fast to write than a fast function that was slow and error prone to write. I can always speed up working code (or, failing that, fall back to the original slow code) much easier than taking fast code and making it work ;-)

        (Note - this is in no way intended to say that the above code doesn't work, only that I've seen many people get fooled when trying to use the *dir functions - including myself.)

      Oy! Do I feel like an idiot.

      It WAS a directory issue. I'd forgotten that my code was moved to a different drive with the same directory structure over the weekend.

      Thanks for all the help.

        It makes for a very interesting study in the pathology of "programmer's self-delusion", trying to reconcile this remark ("I'd forgottern that my code was moved to a different drive..."), with the remark you made about 80 minutes earlier: Yes, I added a print statement that verified I'm getting into the correct directory, and yes, the directory has "test.dat" in it.

        We all do it -- some more than others, perhaps, but no one is immune. The trick is to remember this fact, to recognize when it strikes, and to work out some ploy to circumvent the personal defect... like "Hmm, if someone else besides me were looking at this, what would they ask/look for/test..."

Re: Pulling a file with a given extension
by nimdokk (Vicar) on Oct 18, 2005 at 15:51 UTC
    I just ran your code and it worked for me except I added an "opendir" as well:

    opendir DIR, '.' or die "Cannot open current dir. $!"; my @files = grep { /\.(?:dat)$/i } readdir DIR; closedir DIR; my $datfile = $files[0]; print "\$datfile ==> $datfile\n";
Re: Pulling a file with a given extension
by ikegami (Patriarch) on Oct 18, 2005 at 15:51 UTC
    Did you check whether DIR was opened successfully? If you're using a relative directory, are you sure you know the current directory?
      Yes, I added a print statement that verified I'm getting into the correct directory, and yes, the directory has "test.dat" in it.

      Still, when I run it I get "$datfile ==>" and that's it.

        Do you see "test.dat" outputted when you do
        opendir DIR, '.' or die "Cannot open current dir. $!"; print("$_\n") foreach readdir DIR; closedir DIR;

        If so, I suspect the filename isn't actually "test.dat". Maybe it has a trailing space. Maybe there's some funky character in there that's not getting displayed.

Re: Pulling a file with a given extension
by amw1 (Friar) on Oct 18, 2005 at 16:09 UTC
    To do this recursively. . . find2perl /some/dir -name "*.dat"
    #! /usr/bin/perl -w eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' if 0; #$running_under_some_shell use strict; use File::Find (); # Set the variable $File::Find::dont_use_nlink if you're using AFS, # since AFS cheats. # for the convenience of &wanted calls, including -eval statements: use vars qw/*name *dir *prune/; *name = *File::Find::name; *dir = *File::Find::dir; *prune = *File::Find::prune; sub wanted; # Traverse desired filesystems File::Find::find({wanted => \&wanted}, '/some/dir'); exit; sub wanted { /^.*\.dat\z/s && print("$name\n"); }
    Put your processing code into wanted.
Re: Pulling a file with a given extension
by cognizant (Pilgrim) on Oct 19, 2005 at 03:46 UTC
    If you want to check the filename inside subdirectory too, then you can use the following code.
    $input = $ARGV[0]; #input directory find(sub {push(@ara, $File::Find::name) if -d}, $input); foreach $arr (@ara) { opendir (FIN, "$arr") || die("can't open $arr"); my @cnt = readdir(FIN); chdir($arr); foreach $temp (@cnt) { print "$temp" if ($temp=~/\.dat$/); } }
    Cheers --C