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

Fellow monks, I am trying to capture output from a spawned child. But no luck, can someone help me? So I ended up processing everything at the child level. Below is a code snipet:
#!/usr/bin/perl -W use scr_rsh; my @properties = ("run","conf"); my $cmd_run = "ps -ef|grep match | grep \" 1 \"|wc -l"; my $cmd_conf = "wc -l /usr/local/match.conf"; my ($pid,@pid); my $passwd = ask; print "\n"; # hash of hashes our $domatch = {}; # Hash of Hashes # set default values of HoH for(my $key1 = 0; $key1 <= $#ARGV; $key1++) { foreach my $key2 (@properties) { my $domatch = { $ARGV[$key1 ] => {$key2=>'0'} }; } }# Fork processes for($key1=0, $i = 1; ($i <= 2) && ($key1 <= $#ARGV); $i++,$key1++) { $pid=fork(); push @pids, $pid; if($pid == 0) { #Child Process $domatch->{$ARGV[$key1]}->{"conf"} = &get_proc_run($passwd,$ARG +V[$key1]); #wanted to pass this result to parent $domatch->{$ARGV[$key1]}->{"run"} = &get_proc_conf($passwd,$ARG +V[$key1]); #wanted to pass this result to parent &prt_result($ARGV[$key1]); # wanted to execute this after all ch +ild are done exit(0); } if("$i" == "2") { $i=0; } } foreach my $childpid (@pids) { waitpid($childpid,0); }

Replies are listed 'Best First'.
Re: parent wants to capture output from a spawned child
by chromatic (Archbishop) on Nov 24, 2001 at 11:17 UTC
    The answers to forking: retaining variables after the child exits still apply. I'd go with pipe, if I were you.

    You can also safely whack the "set default values of HoH", because it's not doing anything, useful or otherwise. Hash keys automagically spring into existence when you need them (in your child processing code). Besides that, you're creating a new anonymous hash for the lexical $domatch on each iteration of the inner loop. It doesn't touch the $domatch you've defined outside the loop. That's lucky. If it did, it would overwrite it on each iteration. Of course, hash autovivification saves you from that trouble later on.

    It looks like you have a structured programming background (probably C, but something of that family). The second section of perlport has lots of good information that can help you out, if you're interested.

Re: parent wants to capture output from a spawned child
by Zaxo (Archbishop) on Nov 24, 2001 at 12:02 UTC

    If you fork by way of magical open the kids can print their messages and you can read them on the filehandle:

    #!/usr/bin/perl -w use strict; my %kids = (); my @msgs = (); $SIG{CHLD} = q/IGNORE/; for ( 'a', 'b', 3) { my ( $pid, $fh); defined($pid = open $fh, "-|") or warn $! and last; if ($pid) { # be parental $kids{$pid} = $fh; next; } else { kid_code($_); } } push @msgs, <$_> for values %kids; print @msgs; sub kid_code { # do childish things, then (goes to $fh in parent) print "$_[0]. Your Message Here$/"; exit(0); }
    IO:Select would improve this. You might also look at Parallel::ForkManager.

    After Compline,
    Zaxo

      Thanks for the help, I ended up using "open" instead of "pipe" because pipe was slower (not sure if I am doing something wrong with it). Quick follow up question? I notice "push @msgs, <$_> for values %kids" deference the filehandle where as something like: " for (values %kids) { print "<$_>\n"; }" returns a ref. Is my assumption correct?

        Nearly right. In push @msgs, <$_> for values %kids; the diamond operator is evaluated in list context, giving you all messages. In print "<$_>\n"; the diamond is not evaluated inside double quotes. Instead, you get literal '<' followed by the interpolated $_, then literal '>'. $_ is a filehandle, a stringified ref to a typeglob is printed. You can do what I think you want with print "@{[<$_>]}\n"; or just print <$_>;

        After Compline,
        Zaxo

Re: parent wants to capture output from a spawned child
by Dogma (Pilgrim) on Nov 24, 2001 at 16:02 UTC
    Whats going on here is that both the parent and the child are executing everything below the "if($pid == 0)" point. When you call fork the current process is copied. That means everything you want to execute or not will end up in the child process. I would recommend reading perlipc or looknig at the examples in the perl cookbook. To keep in line with your coding try.
    $pid=fork();
    if($pid == 0) {
       # This is the child
    } else {
       # This is the parent
    }