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

Hi, i am trying to get a perl script that will go into every subdirectory in a directory called "antarctica". In each subdirectory, I need to execute a for loop. having trouble figuring out how to get perl to go into each subdir one by one.

  • Comment on Execute a for loop in many subdirectories

Replies are listed 'Best First'.
Re: Execute a for loop in many subdirectories
by choroba (Cardinal) on May 22, 2014 at 20:12 UTC
    You will need -d to test for directoryness. You can also use glob
    while (defined(my $subdir = glob 'antarctica/*')) { next unless -d $subdir; chdir $subdir; for ... chdir '../..'; }

    or opendir and readdir:

    opendir my $D, 'antarctica' or die $!; while (defined(my $dir = readdir $D)) { $dir = "antarctica/$dir"; next unless -d $dir; chdir $dir; for ... chdir '..';
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      This looks like what I was trying to do... is there a distinct difference between these 2 approaches? Thank you!

        I am not sure. readdir might be better if there are millions of files in the antarctica directory, if I remember correctly.
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Execute a for loop in many subdirectories
by dasgar (Priest) on May 22, 2014 at 20:11 UTC

    Don't know how many levels of subdirectories that you plan to search through, but you'll probably find File::Find (or File::Find::Rule, which I personally prefer to use) and the -X file test function to be useful.

      The depth is only 1, I don't need to go deeper than /antarctica/*

        The depth is only 1, I don't need to go deeper than /antarctica/*
        No need for File::Find then:
        my @dirs = grep -d, </antarctica/*>; for my $dir (@dirs) { chdir($dir) or die "Failed to chdir to $dir: $!"; execute_something(); }
Re: Execute a for loop in many subdirectories
by Anonymous Monk on May 22, 2014 at 20:08 UTC
Re: Execute a for loop in many subdirectories (find/rule)
by Anonymous Monk on May 22, 2014 at 21:31 UTC

    find/rule for everything

    #### if the number of dirs you expect fits in memory

    #!/usr/bin/perl -- use strict; use warnings; use Path::Tiny qw/ path cwd /; use File::Find::Rule qw/ find rule /; use autodie qw/ chdir /; my $cwd = cwd(); ## all dirs #~ my @dirs = find( directory => in => 'antarctica' ); ## only depth 1 my @dirs = find( directory => maxdepth => 1 , in => 'antarctica' ); for my $dir( @dirs ){ Voltronize( $dir ); } chdir $cwd;

    #### if the number of dirs you expect is huge

    #!/usr/bin/perl -- use strict; use warnings; use Path::Tiny qw/ path cwd /; use File::Find::Rule qw/ find rule /; use autodie qw/ chdir /; my $cwd = cwd(); ## iterator my $dirs = rule( directory => maxdepth => 1 )->start( 'antarctica' ); while( defined( my $dir = $dirs->match ) ){ Voltronize( $dir ); } chdir $cwd;

    Or readdir/glob with Path::Tiny (easier than actual readdir , more memorable than glob )

    #!/usr/bin/perl -- use strict; use warnings; use Path::Tiny qw/ path cwd /; use autodie qw/ chdir /; my $cwd = cwd(); my @dirs = grep { -d $_ } path( 'antarctica' )->children(); for my $dir( @dirs ){ Voltronize( $dir ); } chdir $cwd;

    The Path::Tiny iterator is no find/rule but still beats readdir/glob

    #!/usr/bin/perl -- use strict; use warnings; use Path::Tiny qw/ path cwd /; use autodie qw/ chdir /; my $cwd = cwd(); my $dirs = path( 'antarctica' )->iterator( { recurse => 0, follow_symlinks => 0, } ); while( defined( my $path = $dirs->() ) ){ Voltronize( $path ) if $path->is_dir; } chdir $cwd;
      alternative way if the number of dirs you expect is huge ; no iterator required :) nothing returned because $Vol discards ...
      #!/usr/bin/perl -- use strict; use warnings; use File::Find::Rule qw/ find rule /; find( directory => maxdepth => 1 , exec => sub { Voltronize($_); return !!0; ## means discard }, in => [ 'antarctica' ], );
Re: Execute a for loop in many subdirectories
by hippo (Archbishop) on May 22, 2014 at 22:06 UTC

    As ever, start with the FAQ.