#!/usr/local/bin/perl # # NAME: # parallel - run command line for each arg from stdin # # SYNOPSIS: # parallel.pl [-n "n"] "command" < "arglist" # # DESCRIPTION: # This script simply executes "command" for each element of # "arglist". If "command" contains the sequence '{}' then "arg" # is instantiated at that point. The default is to tack "arg" # to the end of "command". Note that "command" should almost # always be protected by single quotes. # # We run "n" instances of "command" in parallel. # # This is a translation of an earlier shell script. We do all # output from the controlling thread to avoid merged output and # we avoid busy waiting for empty job slots. # # BUGS: # "command" should start with a pathname, otherwise a shell # ``feature'' results in it not knowing its own location. Many # scripts like to know this so they can find related files. # # AUTHOR: # Simon J. Gerraty # # RCSid: # $Id: parallel.pl,v 1.4 1998/08/26 13:33:44 sjg Exp $$ # # @(#) Copyright (c) 1997 Simon J. Gerraty # # This file is provided in the hope that it will # be of use. There is absolutely NO WARRANTY. # Permission to copy, redistribute or otherwise # use this file is hereby granted provided that # the above copyright notice and this notice are # left intact. # # Please send copies of changes and bug-fixes to: # sjg@quick.com.au # if ($0 =~ m,^(.*)/([^/]+)$,) { $Mydir = $1; $Myname = $2; } else { $Mydir = '.'; $Myname = $0; } require 'getopts.pl'; if ($Myname =~ m/foreach/) { $opt_n = 1; } else { $opt_n = 4; } $tf = "/tmp/.$Myname$$."; &Getopts('n:d:'); &main; exit 0; sub main { $cmd = join(' ', @ARGV); if ($cmd !~ m/{}/) { $cmd .= ' {}'; } if ($opt_n < 2) { &foreach; } else { ∥ } } # this is just for backwards compatability sub foreach { while () { chop; $c = $cmd; $c =~ s/{}/$_/g; system($c); } } sub parallel { $n = 0; %Job = (); #$SIG{'CHLD'} = 'IGNORE'; # breaks wait() on Solaris open(D, "> $opt_d") if ($opt_d ne ''); while () { chop; $c = $cmd; $c =~ s/{}/$_/g; while ($n >= $opt_n) { $p = wait; &finish($p); $n--; } for ($j = 0; $j <= $opt_n; $j++) { last if ($Job{$j} eq ''); } $f = "$tf$j"; if (($p = fork()) == 0) { exec("$c > $f 2> $f.e"); } print D "started: Job=$j, pid=$p, file=$f\n" if ($opt_d ne ''); $Job{$j} = $p; $File{$j} = $f; $n++; } while (($p = wait) > 0) { &finish($p); } unlink(<$tf*>); } sub finish { local($pid) = @_; print D "finish: pid=$p\n" if ($opt_d ne ''); foreach $j (keys(%Job)) { if ($Job{$j} == $pid) { $file = $File{$j}; $err = "$file.e"; $Job{$j} = ''; &cat(STDOUT, $file); &cat(STDERR, $err); return; } } print STDERR "$Myname: did not find Job[$pid]\n"; } sub cat { local(*h,$file) = @_; if (-s $file && open(I, "< $file")) { while () { print h; } close I; } }