CheeseConQueso
CheeseConQueso

Reputation: 6051

How can I get a list of all files with a certain extension from a specific directory?

I'm using this code to get a list of all the files in a specific directory:

opendir DIR, $dir or die "cannot open dir $dir: $!";
my @files= readdir DIR;
closedir DIR;

How can I modify this code or append something to it so that it only looks for text files and only loads the array with the prefix of the filename?

Example directory contents:

.
..
923847.txt
98398523.txt
198.txt
deisi.jpg
oisoifs.gif
lksdjl.exe

Example array contents:

files[0]=923847 
files[1]=98398523
files[2]=198

Upvotes: 16

Views: 49990

Answers (6)

Kebman
Kebman

Reputation: 2089

This is the simplest way I've found (as in human readable) using the glob function:

 # Store only TXT-files in the @files array using glob
 my @files = grep ( -f ,<*.txt>);
 # Write them out
 foreach $file (@files) {
  print "$file\n";
 }

Additionally the "-f" ensures that only actual files (and not directories) are stored in the array.

Upvotes: 3

Robert P
Robert P

Reputation: 15988

To get just the ".txt" files, you can use a file test operator (-f : regular file) and a regex.

my @files = grep { -f && /\.txt$/ } readdir $dir;

Otherwise, you can look for just text files, using perl's -T (ascii-text file test operator)

my @files = grep { -T } readdir $dir;

Upvotes: 2

Hynek -Pichi- Vychodil
Hynek -Pichi- Vychodil

Reputation: 26141

Just use this:

my @files = map {-f && s{\.txt\z}{} ? $_ : ()} readdir DIR;

Upvotes: 1

Brad Gilbert
Brad Gilbert

Reputation: 34130

If you can use the new features of Perl 5.10, this is how I would write it.

use strict;
use warnings;
use 5.10.1;
use autodie; # don't need to check the output of opendir now

my $dir = ".";

{
  opendir my($dirhandle), $dir;
  for( readdir $dirhandle ){ # sets $_
    when(-d $_ ){ next } # skip directories
    when(/^[.]/){ next } # skip dot-files

    when(/(.+)[.]txt$/){ say "text file: ", $1 }
    default{
      say "other file: ", $_;
    }
  }
  # $dirhandle is automatically closed here
}

Or if you have very large directories, you could use a while loop.

{
  opendir my($dirhandle), $dir;
  while( my $elem = readdir $dirhandle ){
    given( $elem ){ # sets $_
      when(-d $_ ){ next } # skip directories
      when(/^[.]/){ next } # skip dot-files

      when(/(.+)[.]txt$/){ say "text file: ", $1 }
      default{
        say "other file: ", $_;
      }
    }
  }
}

Upvotes: 5

catwalk
catwalk

Reputation: 6476

it is enough to change one line:

my @files= map{s/\.[^.]+$//;$_}grep {/\.txt$/} readdir DIR;

Upvotes: 6

Wooble
Wooble

Reputation: 90037

my @files = glob "$dir/*.txt";
for (0..$#files){
  $files[$_] =~ s/\.txt$//;
}

Upvotes: 12

Related Questions