1

The setup:

A data directory that contains directories for every day of the year. ie data/2014-01-01/ to 2014-12-31. I have a perl script that I run individually inside each date directory.

I am attempting to run a shell script to run from data and go through each directory from 2014-02-15 to 2014-07-20 and run the perl script inside each directory. The perl script takes about 20 seconds to run. This is what I have so far, it will only run on February so far, and doesn't wait for the perl script to finish. I would like it to run on every directory in the range and wait for the perl script inside the loop to finish before relooping.

 #!/bin/bash

 folders=`find 2014-02*`

 for folder in $folders; do 
 cd $folder
 perl C:/Tools/script.pl
 cd ..
 done
14
  • 1
    Why not add the folder traversing to the perl script rather than a separate shell script? Is each folder's perl script materially different? Commented Feb 3, 2015 at 19:55
  • 1 Don't iterate find results like that, see this answer. 2 cd .. won't take you back if you previously cded deeper than one directory. Commented Feb 3, 2015 at 19:56
  • 1
    find data/ -type d -name '2014-0[2-7]-(1[5-9]|20)' -exec C:/Tools/script.pl {} \; The above command will work I believe (did not test), but it seems more reasonable to build a script that can take an arbitrary start and end point and apply whatever logic you want. Since it seems likely you will have to do this again. Commented Feb 3, 2015 at 19:56
  • @Biffen Thanks for the info but do you have any solutions? Commented Feb 3, 2015 at 19:57
  • @Hunter I'll try this. Will this wait for the perl script to finish over each iteration? And yes I'd like to have it implemented in a script to run again later. Commented Feb 3, 2015 at 19:58

1 Answer 1

3

Why not do it all in perl? It has perfectly good traversal capability with the File::Find built in module.

Encapsulate your 'script' as a subroutine.

#!/usr/bin/perl

use strict;
use warnings;
use File::Find;

sub your_script_sub {
    my ( $dir ) = @_;
    #do something with $dir. At a worst case, you could just run your script.
    #but there's no real reason to do that, as it's perl already. 
}

sub run_script_in_dirs {
   if ( -d $File::Find::name ) { 
        your_script_sub($File::Find::name);
    }
}

find ( \&run_script_in_dirs, "/path/to/your/dir" );

For bonus points - you could use a thread to parallelise your 'run script in directory:

#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;

my $num_threads = 4;
my $dir_q = Thread::Queue -> new(); 

sub your_script_sub {
   while ( my $dir = $dir_q -> dequeue() ) {
          # do something in $dir;
   }
}

sub find_dirs_to_run_script {
   if ( -d $File::Find::name ) { 
        $dir_q -> enqueue($File::Find::Name);
    }
}

for ( 1..$num_threads ) {
   threads -> create ( \&your_script_sub );
}

find ( \&find_dirs_to_run_script, "/path/to/dirs" );

$dir_q -> end();

foreach my $thr ( threads -> list() ) { $thr -> join() }
Sign up to request clarification or add additional context in comments.

6 Comments

Looks good. It doesn't look like the range of the directories is included in this though right? Also my other perl script uses another program for analysis so it can only be used once at a time.
No. The way perl does it, is with that subroutine, and you can test either $_ or $File::Find::name for matching the pattern you're seeking. Are you sure your other program can only be used one at a time? Is that some licensing issue?
Yes it uses another program for analysis that goes through and calculates a ton of data. Can't run to sets of data at once.
shrug. Well, the first example then. But like I say - it's not particularly common that you have a program that can only run one instance at a time. (Aside from resource constraints). This will traverse anything under /path/to/dirs that is a directory.
if ( -d $File::Find::name ) { your_script_sub($File::Find::name); } I'll change name to be the 2015-02-15 to 2015-07-20 range?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.