Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How do I call external script and continue ignoring return 3

Status
Not open for further replies.

derekpc

Technical User
Jul 3, 2001
44
GB
I would like to call an external perl script from within a loop, passing it one argument and then continue with the loop without waiting for the external script to return. I don't need to capture anything from the external script as it records it's actions in a separate log file. I think from having researched it that I may need to fork, but I've not used fork in the past and have to admit I don't really understand what I have been reading.
Basically the first script is parsing html files and building a url for the file from meta data containing the path and file name. The loop may process quite a few files. The second script takes a single url as an argument and builds a form submission with lwp and passes that url and some other arguments to a remote asp. So, I want to be able to fire this off multiple times from within the loop without any pause in the processing waiting for results from the external script. Can someone point me in the right direction?
Thanks.
Derek
 
fork() is definitely the way to go. When you call it, it makes a copy of the current program running at the same point. The only difference is that it returns the child process' ID to the parent, and 0 to the child. At its simplist:
Code:
exec('script2') unless(fork);
fork() returns the pid of the child to the parent, which is a true value, which fails with unless(). The only time the block is executed is if fork() returns false, and fork() returns 0 to the child (or undef on failure, so in reality, you should check for that). The child runs exec(), which is like system() without returning.

There's new threading with Perl 5.8 that might be worth a look if you ever have to share data. There's also IPC that you can work with, too. But your case is simple enough that fork() is your best bet. Play around and see.

________________________________________
Andrew - Perl Monkey
 
Yeah, fork is the way to go...you should probably take care to watch the children after your loop to make sure they eventually finish and catch on the errors...also if you are doing any perl code in the child other than just exec a system script then just use this kind of form:

Code:
if($ChildsPid = fork()) {

   # I'm the parent code...record the child process id to
   # track later...
   $child_fork_ids{$ChildsPid}=1

} else {

   # I'm the child, I should get to work!

   # do any child perl code here...

   # call the external script...use backticks to catch
   # the stdout of the process (maybe for error checking
   # or whatever) and you can catch the status in $?
   $output=`$cmd`;
   $stat = $? >> 8;
   
   # maybe some more code here...

   exit $stat;  # child exit status can be caugt by parent below...

}


# now after all your looping you probably want to 
# check all the kids to see if they finished and what
# their status was...

use POSIX "sys_wait_h";

$done=0;
while(! $done) {
    $done=1;
    print "Checking my kids..\n";
    foreach $id (keys %child_fork_ids) {
	print "Checking on $id\n";
        $status = waitpid $id,WNOHANG;
	print "got status $status\n";
        $stat = $? >> 8;
	print "stat was $stat\n";
        if ($status == -1) {
            print "\tChild $id gone (ignore stat)\n";
            delete $child_fork_ids{$id};
        } elsif ($status == $id) {
	    print "\tChild $id is done and got $stat\n";
	} elsif ($status == 0) {
	    print "\tChild $id is still running...(ignore stat)\n";
            $done=0;
        }
    }
    sleep 1;
}


the waitpid command will wait for a child process to end and if you say WNOHANG it will not really wait, it'll just return 0 if the child is still running or it'll return the childs pid if it just ended (in which case $? >> 8 will be the status of the child), or -1 meaning not there at all.

 
Alternatively, you could just launch script2 as a background process (assuming you're on a *nix system)
Code:
system('script2 &');
script2 will now go on its merry way and your first script continues on without caring what happens script2.

Of course it's more difficult to track errors etc. from script2, since script1 is now ignoring it.
 
Andrew, CadGuy and Ishnid,
Thank you all very much for the tips. I am going to have to study some more on the exec and fork as when I tried the exec unless(fork) I ended up with many more processes running than I expected. Probably a problem in my loop code some where that I will have to dig through but you've given food for thought. To be honest, I took the cowards way out, dumped my processed URLs to separate files and am processing them with a separate script. Works, but I am still going to look back on exec and fork. Will also give the background process a try.
Thanks again.
Derek
 
derek,

remember that each time your loop iterates, it will spawn a new fork(). be sure to isolate the fork() process if you just want one fork() running at a time.

There's always a better way. The fun is trying to find it!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top