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

Hi folks, I need to store up the files in two directories into one array. I have code like the below,
my Dir1 = "d:/xxxxxx"; my Dir2 = "d:/xxxxxx"; my @files = glob ("$Dir1/*" \& "$Dir2/*"); for my $file (@file) {print $file, "\n"}
I do not know how to put two directories files into one array correctly. Please help. Thanks

Replies are listed 'Best First'.
Re: list two paths files into one array (updated)
by haukex (Archbishop) on Nov 13, 2017 at 20:44 UTC

    The built-in glob splits its arguments on whitespace, so one might think of this as a possibility, but especially since you seem to be on Windows, I wouldn't be surprised if the pathnames contain spaces. I would recommend bsd_glob from File::Glob instead, which does not split on whitespace:

    use File::Glob 'bsd_glob'; my @files = ( bsd_glob("$Dir1/*"), bsd_glob("$Dir2/*") );

    You can also use File::Glob ':bsd_glob'; to override the builtin glob (except on really old versions of Perl). Another possible caveat of glob to be aware of is that it does not list files beginning with a dot by default.

    Update: Another possibility might be: my @files = bsd_glob("{$Dir1,$Dir2}/*"); Also a few edits to add a bit of info.

    Update 2: An even bigger possible caveat that should be mentioned is that of course all this assumes that $Dir1 and $Dir2 don't contain any characters that have special meaning to glob. If that is the case, I'd recommend other methods like Path::Class::Dir's children method (this will include filenames beginning with a dot, use ->children(no_hidden => 1) to suppress them):

    use Path::Class qw/dir/; my @files = ( dir($Dir1)->children, dir($Dir2)->children );
      Thanks, File::Glob 'bsd_glob' works
Re: list two paths files into one array
by pryrt (Abbot) on Nov 13, 2017 at 20:58 UTC
    1. In case you haven't noticed during your four months in the monastery: always use strict; use warnings;
    2. How would you do it if there's just one directory? Can you get that code working? (hint: it requires fixing compiler errors in your example, and then simplifying your glob statement.
    3. Do you know how to then add more entries into your array with a second line of code? (hint: there's builtin functions for appending and/or prepending a list of values to arrays: see perlfunc).

    if steps 1-3 get it for you, great. If not, show the working code (SSCCE) for #2 and the failing code for #3, and explain what your thought process was, and why you tried what you tried. If you cannot even get #2, post your failing code, and include the errors you are getting.

    (haukex made some good glob-specific points while I was writing this, before I posted, that are likely to get you to the solution, too. TIMTOWTDI, and what I've presented is the series of steps I would take to debug the problem, if were it mine: simplify to a single directory; expand to multiple directories using the simplest perl syntax you can come up with. I'd recommend going through those steps to improve your coding and debug skills, even if haukex's suggestion works for you.)

Re: list two paths files into one array
by 1nickt (Canon) on Nov 14, 2017 at 00:20 UTC

    Hi, please take a look at the documentation for Path::Iterator::Rule, which can be used simply to "store up" the file names as shown below, or can filter for various different criteria first (not_empty, min size, etc).

    use strict; use warnings; use Path::Iterator::Rule; my @dirs = ( '/somepath/to/dir1', '/other/path/to/dir2', ); my $rule = Path::Iterator::Rule->new->file; for my $file ( $rule->all( @dirs ) ) { say $file; # etc. } __END__

    Hope this helps!


    The way forward always starts with a minimal test.
Re: list two paths files into one array
by Laurent_R (Canon) on Nov 13, 2017 at 23:56 UTC
    As a preliminary note, I would say that your code doesn't compile. Even the very first line doesn't compile.

    Otherwise, what you can do is to store the entries of the first dir into an array, and then add the entries of the second one to this array. Something like this:

    my $Dir1 = "d:/xxxxxx"; my $Dir2 = "d:/yyyyyy"; my @files = glob ("$Dir1/*"); for my $file (glob "$Dir2/*" ) { push @files, $file; } for my $file (@file) { print $file, "\n" }
    Of course, this can be made somewhat shorter:
    my $Dir1 = "d:/xxxxxx"; my $Dir2 = "d:/yyyyyy"; my @files = glob ("$Dir1/*"); push @files, $_ for glob "$Dir2/*"; print $_, "\n" for @file;

      push accepts a list as the second "argument" (and provides list context in that position), so there's no need for the for loop around the second glob: push @files, glob "$Dir2/*"; is sufficient. Of course, now we've given the spoiler for my step #3... oh, well.

        Yes, this is right: there is no real need for the for loop in this case. I thought that it was still better to show the process in an explicit loop since the OP is really a beginner. TIMTOWTDI, there are in fact many ways to do it.

        Sorry for "spoiling" your answer, I did not think about that, but just thought that the OP deserved a simple example solution.