tags:

views:

108

answers:

5

I've tried using system() with fork(), tried exec(), and still not getting what I need.

I want to write a Perl script which executes, let's say, a different Perl script 5 times in a row (sending it different parameter values), but have it run concurrently. I realize I could turn my script into a .pm file and reference it but I'd prefer to keep the child script independent of the parent...

  • system() works, but executes the commands consecutively (makes sense per doc)
  • exec() doesnt work - it only executes the first method (makes sense per doc)
  • I added a fork() to the child perl script and then tried using system()
  • this did not work either.
  • backtick command ' documents says it works the same as system()...

Isn't there a simple way in Perl (im using WindowsXP) to execute a process, and not care about the return values or antyhing and just continue on into the next line of the parent script?

+2  A: 

You need to fork in the parent, then exec in the new process. It goes like this, assuming A is the original script, and B is the one you want to do 5 times:

                A1
fork in A1   -> A1 A2
exec B in A2 -> A1 B2
fork in A1   -> A1 A3 B2
exec B in A3 -> A1 B3 B2

etc.

Matthew Flaschen
How can I fork in the parent? fork doesn't take params, so How do I tell it which command to execute...
dferraro
You first call [`fork`](http://perldoc.perl.org/functions/fork.html). That duplicate the process as shown, then `fork` returns twice. You then use the return value to determine which process you're in. If it's non-zero, it's the parent; if 0, then the child. Then, in the child, you call [`exec`](http://perldoc.perl.org/functions/exec.html). Eric provided a concise example.
Matthew Flaschen
+11  A: 

you can do it like this (fork in the parent, exec in the child):

for my $cmd qw(command1 command2 command3) {
       exec $cmd unless fork
}

the way that exec $cmd unless fork works is that fork will return a true value in the parent (the process id) and will return a false value in the child, thus exec $cmd only gets run if fork returns false (aka, in the child).

or if you want to keep tabs on the process as it runs concurrently:

my @procs;

for my $cmd qw(cmd1 cmd2 cmd3) {

   open my $handle, '-|', $cmd or die $!;

   push @procs, $handle;
}

then you can read from an element of @procs if you need to.

Or take a look at one of the many cpan modules like Forks::Super that handle the details of fork management.

Eric Strom
Just be aware that fork() on Windows has some complications, and since the open is simply a fork under the covers, you'll see them there, too.
Tanktalus
+6  A: 

On Windows, you can give the super-secret 1 flag to system, IIRC.

system 1, @cmd;

A quick google search for this question on perlmonks gives: http://www.perlmonks.org/?node_id=639814

Hope that helps.

Tanktalus
this worked awesome. Thanks. First time using perl, this works great. thanks to everyone else who replied after my comment
dferraro
@dferraro => welcome to the magical land of Perl, hope you enjoy your stay. In general, I would recommend that you stay away from operating system specific solutions if a more general solution exists. You never know when you will need the script to work on an unforeseen platform.
Eric Strom
thanks for the welcome... I'd like to run away like hell now. I still haven't seen a single line of perl that didn't take me 5 minutes to overstand ;)
dferraro
+2  A: 

A module is overkill for this job. You want to fork to create a new process and then exec to run a command in the new process. To run five commands, you need something like:

 for (my $i=0; $i<5; $i++) {
     if (fork() == 0) {
         exec($command[$i]);   # runs command, doesn't return
     }
 }
socket puppet
A module is not overkill if you want cross-platform behaviour that hides all the platform-specific behaviour that fork emulation on Windows brings. Hiding complexity behind a (hopefully) simple interface is one of the purposes of modules.
Tanktalus
If you have version 5.8 or later, there is nothing wrong with fork and exec on Windows.
socket puppet
+2  A: 

A very lightweight approach.

Windows:

foreach my $cmd (@cmds)
{
    `start $cmd`;
}

Unix:

foreach my $cmd (@cmds)
{
     `$cmd &`;
}
tster
I did try this cause it looked simple too, but it didnt open any console windows and then it hung on the last execution... ?
dferraro
Generally, I like to avoid backticks just to avoid the shell. Especially on Windows where $cmd may have spaces in it.
Tanktalus