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

Hi Perl Monks, I'm trying to list the contents of a directory (/opt/tmp). I have tried the following options:

Option 1

my @files = grep(-f, <*.*>); foreach my $file (@files) { print "file = $file\n"; }

This code only list the files in my current directory /opt/, but i need to list the files in directory /opt/tmp/

Option 2

my @files = glob("/opt/tmp/*.*"); foreach my $file (@files) { print "file = $file\n"; }

This code doesn't print anything. I'm not even sure the glob works.

Option 3

my @files; opendir(DIR, "/opt/tmp/" or die "Cannot open dir"); @files = grep {-T "/opt/tmp/$_"} readdir DIR; foreach my $file (@files) { print "file = $file\n"; } closedir(DIR);

When i execute this code i always get an error: "Cannot open dir". However, the directory exists and has files in it.

I also tried some other options related to opendir, but the output was empty.

Can someone help me?

Thanks

Replies are listed 'Best First'.
Re: Perl List files in directory
by Anonymous Monk on Apr 22, 2014 at 10:44 UTC

    In your Option 2, try my @files = glob("/opt/tmp/*");, otherwise you'll only get files that include a dot in the name.

    In your Option 3, the opendir line should be: opendir(DIR, "/opt/tmp/") or die "Cannot open dir"; (misplaced closing paren). Also, the grep causes @files to only include "text" files (see documentation of -T in -X), is that what you want?

      No, my directory contains xml files. I will take a look at the documentation.

      Thanks for the help

        Depending on the encoding of your XML files, the -T test may or may not recognize them as "text" files. From -X:

        The -T and -B switches work as follows. The first block or so of the file is examined for odd characters such as strange control codes or characters with the high bit set. If too many strange characters (>30%) are found, it's a -B file; otherwise it's a -T file. Also, any file containing a zero byte in the first block is considered a binary file.
Re: Perl List files in directory
by bigj (Monk) on Apr 22, 2014 at 11:06 UTC
    In addition to the others, you might also try not to reinvent the wheel. Whenever you need to search files, the 1st recommandation should be File::Find. In your case
    use File::Find; find({wanted => sub {-f and print "file = $_\n"},follow => 1},'.');
    already does what you intend to do in a shorter, easier readable, more maintainable and much less errorprone way.

    Greetings,
    Janek Schleicher

      1st recommandation should be File::Find. In your case

      Are you sure about that? Because that doesn't have /opt/tmp or @files

      My first recommendation is always File::Find::Rule

      use File::Find::Rule qw/ rule find /; my @files = find( file => maxdepth => 1, ascii => in => '/opt/tmp' );
        O.K., you'd have to change '.' from my snippet to '/opt' or '/opt/tmp' or $dir to work it on other than current dir. Whether you use File::Find or File::Find::Rule is more a matter of taste. The maintainer of the module describes it as a is a friendlier interface to File::Find :-).

        Greetings,
        Janek Schleicher

      ... already does what you intend...

      All three of the OP's examples don't descend into subdirs, this one does. Also, this code doesn't show which subdir the file was found in, so you'd probably want something like this instead:

      find({wanted => sub {-f and print "file = $File::Find::name\n"},follow => 1},"/opt/tmp");
Re: Perl List files in directory
by hippo (Archbishop) on Apr 22, 2014 at 11:26 UTC

    You wrote:

    opendir(DIR, "/opt/tmp/" or die "Cannot open dir");

    whereas what you probably meant was:

    opendir(DIR, "/opt/tmp/") or die "Cannot open dir";

    Better would be:

    opendir(DIR, "/opt/tmp/") or die "Cannot open dir: $!";

    Perhaps better still would be DirHandle but YMMV.

Re: Perl List files in directory
by Anonymous Monk on Apr 22, 2014 at 10:50 UTC

    Could this be a permissions issue?

    Try changing your error message on the opendir to "Cannot open dir: $!" to see the details of what went wrong.

    Try prefixing your code with the line: warn "Can't read /opt/tmp\n" unless -r "/opt/tmp";

    Also, in general, you should use warnings; use strict; at the top of your scripts if you aren't already.

Re: Perl List files in directory
by Preceptor (Deacon) on Apr 22, 2014 at 11:14 UTC

    I tend to favour using glob and a pattern. However, if it's not printing anything, means that the 'glob' hasn't found any matching files. Try running running an 'ls' or an 'echo' of that precise thing. Alternatively, try pruning down '*.*' - is it _really_ 'any file with a dot in it' that you want to find, or something more specific? Try your glob on "/opt/tmp/*" for example, and see what results you get.

Re: Perl List files in directory
by jellisii2 (Hermit) on Apr 22, 2014 at 12:11 UTC
    If you're processing each file, might I recommend the amazingly good File::Find?
    use strict; use warnings; use File::Find; find(&dostuff, '/opt/tmp'); sub dostuff { # $File::Find::name = /opt/tmp/foo # $_ = foo # $File::Find::dir = /opt/tmp }
Re: Perl List files in directory
by Anonymous Monk on Apr 22, 2014 at 11:03 UTC

    Try

    #!/usr/bin/perl -- use strict; use warnings; use Path::Tiny qw/ path /; use Data::Dump qw/ dd /; my @files = path( "/opt/temp" )->children; dd( \@files ); @files = grep { =T $_ } @files; dd( \@files ); __END__

    Path::Tiny will throw an exception if permission is denied, just like the soldiers at Fort Knox :)

      s/=T/-T/
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Perl List files in directory
by Anonymous Monk on Apr 22, 2014 at 12:21 UTC

    glob comes with a few caveats, such as: it doesn't include files beginning with a dot unless you specifically tell it to, e.g. <* .*>. Also, it uses certain metacharacters which one should be aware of (\*?~[]{}). See also File::Glob.

    If you want to list all of the files in a single directory without subdirectories, opendir+readdir is fine for that. no_upwards() from File::Spec is helpful in getting rid of the . and .. directory entries. Otherwise, if you want to recurse into subdirectories, other monks have already shown some examples using File::Find and File::Find::Rule.

Re: Perl List files in directory
by Anonymous Monk on Apr 22, 2014 at 14:20 UTC

    Hi,

    I tried using :

    @files = glob("/opt/tmp/*");

    i don't get any output. I checked the folder permissions and i have : drwxrwxwx

    I also tried:

    opendir(DIR, "/opt/tmp/") or die "Cannot open dir"; @files = grep {"/opt/tmp/*.xml"} readdir DIR;

    I get an error : "Cannot open dir". However, like i mentioned before the folder as all permissions

    I tried using Tiny, but i got an error saying: "can't locate Path/Tiny.pm in @INC

    Im going to try and use find next

      As you have already been advised in Re: Perl List files in directory, please make your error messages more informative:

      opendir(DIR, "/opt/tmp/") or die "Cannot open dir: $!";

      This will tell you the immediate cause of the problem.

        I did that, i only get: "Cannot open dir: No such file or directory at ./script.pl line 28".

        which doesn't had much.

Re: Perl List files in directory
by Anonymous Monk on Apr 22, 2014 at 14:50 UTC

    I managed to get it working with open dir, i placed the files under a new directory.

    the problem is that now I'm getting everything, even sub-directories and i only want the xml files

    opendir(dir, new_dir) or die "Cannot open dir : $!"; @files = grep {"*.xml"} readdir DIR;

    can someone tell me what i'm missing?

      I found the answer:

      @files = grep {-f "$dir/$_" && m/.xml/} readdir DIR;

      Thanks for the help people

        I'd suggest a small tweak to that:

        @files = grep {-f "$dir/$_" && /\.xml$/i} readdir DIR;

        Because otherwise the regular expression would have matched a file named "fooxml.bar" as well. Also, this now matches the extension case-insensitively, just in case.

Re: Perl List files in directory
by proxy-man (Initiate) on Sep 25, 2015 at 09:10 UTC
    Hi Guys, I am just curious, do we have a way to intercept an exception during glob execution? Say, a directory does not belong to our permissions or something like that. My answer is - NO, glob does not allow us to do this. What is about your answer? BR, ~ R.