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

Fellow Monks,

I am using activesate perl 5.8 on windows 2000. I have a perl script masterscript.pl that calls a number of other perl scripts, one after the other, like this:
print "running script1.pl\n"; do 'script1.pl'; print "running script2.pl\n"; do 'script2.pl'; print "running script2.pl\n"; do 'script2.pl'; etc...
This works fine to me, but is there a way that I can get masterscript.pl to capture all the STDOUT and STDERR messages that are outputted to the screen? say into a variable within masterscript.pl itself.

Thanks in advance,
Jonathan

Replies are listed 'Best First'.
Re: STDOUT and STDIN question
by ikegami (Patriarch) on Nov 03, 2004 at 15:14 UTC

    Check out

    my $stdout_and_stderr1; my $stdout_and_stderr2; my $stdout_and_stderr3; { print "running script1.pl\n"; local *STDOUT; close(STDOUT); open(STDOUT, '>', \$stdout_and_stderr1) or die("..."); local *STDERR; close(STDERR); open(STDERR, '>&STDOUT') or die("..."); do 'script1.pl'; } { print "running script2.pl\n"; ...

    The above requires 5.8(.0? .1?). IO::Scalar can be used with older versions of Perl, but it has limitations.

    If you don't mind running the script in a seperate process, I think this works:

    $stdout_and_stderr1 = `script1.pl 2>&1`; $stdout_and_stderr2 = `script2.pl 2>&1`; $stdout_and_stderr3 = `script3.pl 2>&1`;

    Untested

Re: STDOUT and STDIN question
by pg (Canon) on Nov 03, 2004 at 15:02 UTC

    There are couple of different ways, take a look at perlipc.

    For example. Parent:

    use strict; use warnings; my $pid = open(KID_TO_READ, "-|", "perl -w b.pl"); while (<KID_TO_READ>) { print "from parent: $_"; }

    Child:

    use strict; use warnings; print "Hello\n"; print "World\n";

    This gives you:

    from parent: Hello from parent: World

    However this does not handle STDERR, one way to resolve it is to do this in child:

    use strict; use warnings; open STDERR, '>&STDOUT'; print "Hello\n"; print STDERR "World\n";
Re: STDOUT and STDIN question
by gaal (Parson) on Nov 03, 2004 at 14:43 UTC
    Using do means that script1.pl etc. all run in the same process space as masterscript.pl. (Is this intended? Any leftover variables from one script will leak over to the next.) This means you can dup STDOUT and STDERR before running the various scripts, which is only half a solution so far. Before proceeding, is this what you want to do?
      Yeah, it was intentional to run the scripts with the do command, are you saying that there may be advantages to running the scripts with a system command instead?
      Also, I'm fairly new to perl, so I don't understand what you mean when you say I can dup STDOUT and STDERR

      Thanks for your quick response though
      Jonathan
        Yes, do is a bit less useful than two different appoaches: modules, and completely separate scripts.

        If your child scripts have any code in common with each other, and especially if they can share resources (files, data), it makes sense to write a module for each, and let everything run in equal standing in the same process. If, however, you want each task to really be a separate script, don't risk lefover values leaking over, and have the master invoke each script in a completely separate process.

        (You can still share code by using modules if you run separate processes, of course: simply have them use the common code.)

        As for duping, you can copy -- dup -- a filehandle over. perlopentut has details. It doesn't finish solving your original problem but it might help; alternatively pg's suggestion might be a better route.

Re: STDOUT and STDIN question
by zentara (Cardinal) on Nov 04, 2004 at 10:42 UTC
    There is some good general purpose examples on this in "perldoc perlfaq8" look for the section "How can I capture STDERR from an external command?" It might help.

    I'm not really a human, but I play one on earth. flash japh