in reply to Re: Looping through multiple directories
in thread Looping through multiple directories

Hello NetWallah,

Your first assignment to @ARGV is actually an I/O command (because it uses <>).

Sorry, no:

13:35 >perl -MO=Deparse 1848_SoPW.pl use File::Glob (); @ARGV = glob('/cygdrive/c/Users/abc123/Documents/dude/logs/*.log'); while (defined($_ = readline ARGV)) { (); } 1848_SoPW.pl syntax OK 13:35 >

To dotowwxo:

From the documentation for glob:

Note that glob splits its arguments on whitespace and treats each segment as separate pattern. As such, glob("*.c *.h") matches all files with a .c or .h extension.

So, so specify multiple directories, you simply include each in the expression input to glob. But if you have a lot of directories, it may be more convenient to do something like this:

my @dirs = qw( dir1 dir2 ); # add more as required @ARGV = (); push @ARGV, <./1848_SoPW/$_/*\.log> for @dirs;

or, equivalently,

my @dirs = qw( dir1 dir2 ); @ARGV = map { <./1848_SoPW/$_/*\.log> } @dirs;

Update: The problem described by NetWallah above will occur if @ARGV should happen to be empty when the while (<>) { loop is entered. So it’s safer to handle this as a special case:

use strict; use warnings; my @dirs = qw( dir1 dir2 ); @ARGV = map { <./1848_SoPW/$_/*\.log> } @dirs; if (@ARGV) { while (<>) { ... } }

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^3: Looping through multiple directories
by dotowwxo (Acolyte) on Dec 26, 2017 at 06:50 UTC
    Hi, thank you so much for your response. May I ask what  map { <./1848_SoPW/$_/*\.log> } @dirs; does?

      Hello again dotowwxo,

      map and grep are two very useful functions that Perl provides for operating on lists. Whereas grep acts as a filter, map acts as a transformer which changes each list element in some way. For example, in this one-liner:

      14:20 >perl -MData::Dump -wE "dd map { $_ * 2 } 1 .. 5;" (2, 4, 6, 8, 10) 17:20 >

      the integers 1, 2, 3, 4, and 5 are doubled.

      By contrast, here’s an example using grep to filter out odd numbers:

      17:20 >perl -MData::Dump -wE "dd grep { $_ % 2 == 0 } 1 .. 10;" (2, 4, 6, 8, 10) 17:26 >

      In both map and grep, each element in the input list is represented in the block by Perl’s default variable $_. So, the expression map { <./1848_SoPW/$_/*\.log> } @dirs takes each directory name in @dirs and globs it in the expression <./1848_SoPW/$_/*\.log>. The result in this case is that map outputs a list of all the names of log files in the given directories.

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re^3: Looping through multiple directories
by dotowwxo (Acolyte) on Dec 26, 2017 at 09:39 UTC

    Hello, I've tried to your way.. Here's the result

    My code:
    use strict; use warnings; my $dirs1 = </cygdrive/c/Users/attwwwe1/Documents/dude/logs/*.logs>; my $dirs2 = </cygdrive/c/Users/attwwwe1/Documents/dude/logs2/*.logs>; my @dirs = qw($dirs1 $dirs2); @ARGV = map { <./1848_SoPW/$_/*\.log> } @dirs; if (@ARGV){ while(<>){ #somework } } else{ print "none"; }
    It just prints none every single time I run my script... Not sure what's wrong but it doesn't seem to work.

      That’s not my way!

      my $dirs1 = </cygdrive/c/Users/attwwwe1/Documents/dude/logs/*.logs>; my $dirs2 = </cygdrive/c/Users/attwwwe1/Documents/dude/logs2/*.logs>;

      If you’ve decided to glob each directory separately, you need to store the results of each glob operation in an array, not a scalar:

      my @logs1 = </cygdrive/c/Users/attwwwe1/Documents/dude/logs/*.logs>; my @logs2 = </cygdrive/c/Users/attwwwe1/Documents/dude/logs2/*.logs>;

      And then you don’t need to glob again; just put the names of all the log files into @ARGV:

      @ARGV = (@logs1, @logs2);

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Instead of two separate globs, you can do it in one, as in

      </path/to/dude/{logs,logs2}/*.logs> # or </path/to/dude/logs*/*.logs> # or even </path/to/dude/*/*.logs>

      Although the usage I showed above should be ok, glob has a few caveats one should be aware of: It does not list filenames beginning with a dot by default, and it splits its argument on whitespace, which may be important in case you are interpolating variables into the pattern - you can use File::Glob ':bsd_glob'; to alleviate the latter caveat. Make sure to read all of glob and File::Glob.