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

Hi, if I have a function that writes something to STDOUT or STDERR, for example:
use strict; sub foo(){ # this could be a loop that takes some time to finish. print STDERR "Something to worry about\n"; }
How do I capture this in the main script? i.e., in the main script, I'll call foo(), wait for it to exist, and capture everything it printed to STDERR, I'll then process that string.

Replies are listed 'Best First'.
Re: How to capture STDOUT/STDERR of a function
by Zaxo (Archbishop) on Aug 31, 2004 at 05:02 UTC

    STDERR and STDOUT can be localized, like any other global file handle, . That done you can call your function and output will go to the new handle. In perl 5.8,

    my ($errors, $output); sub foo { print STDERR "Something to worry about\n"; } { open local(*STDERR), '>', \$errors; foo(); } warn "STDERR ought to be restored now"; $errors =~ s/Something/Nothing/; print $errors;
    That takes 5.8+ because of the PerlIO trick of opening a file to memory by using a reference to a scalar in the filename slot. In pre-5.8 perls, you can use IO::Scalar or IO::Stringy for the same purpose.

    After Compline,
    Zaxo

      Thanks, I didn't know about that. What I'm trying to do is to catch the output from Test::Harness, something like the following after your example:
      use strict; use Test::Harness; my $out; { open local(*STDOUT),'>',\$out; runtests(); } print $out;
      Somehow all results are still printed out to screen, not to the $out variable. I tried STDERR too, the same result. Thanks.

        Your use of the idiom is correct. The trouble is that Test::Harness does its own IO remapping.

        You could try running tests from the command line and redirecting output from there.

        After Compline,
        Zaxo

        Sorry, forgot to login for the above post.
Re: How to capture STDOUT/STDERR of a function
by Arunbear (Prior) on Aug 31, 2004 at 10:30 UTC
    Perl has the warn function as a shortcut for print STDERR, so here is a different approach which uses a __WARN__ handler:
    use strict; use warnings; $SIG{'__WARN__'} = \&whandler; my ($Errors); warn "Going to call foo()\n"; foo(); print "\nErrors:\n$Errors"; sub foo { # this could be a loop that takes some time to finish. warn "Something to worry about\n"; warn "Something else to worry about\n"; bar(); } sub bar { warn "Darn it.\n" } sub whandler { my $msg = shift; my $caller = (caller(1))[3] || ''; if($caller eq 'main::foo') { $Errors .= $msg; } else { warn $msg } }
    Here only calls to warn made directly by foo() will be stored.
Re: How to capture STDOUT/STDERR of a function
by sintadil (Pilgrim) on Aug 31, 2004 at 16:46 UTC

    Hi, if I have a function that writes something to STDOUT or STDERR, for example:

    If you want to capture both STDOUT and STDERR, why not have a look at IPC::Open3? You need Open3 (AFAIK) if you want to capture STDERR. As a plus, I'm fairly certain that IPC::Open3 doesn't require a version of Perl >= 5.8. In fact, I just grepped through my perldelta pages and my perl561delta specifies that it was first included at that release.

Re: How to capture STDOUT/STDERR of a function
by gmpassos (Priest) on Aug 31, 2004 at 17:36 UTC
Re: How to capture STDOUT/STDERR of a function
by DrHyde (Prior) on Sep 01, 2004 at 08:45 UTC
    IO::Capture, which is the answer I gave the last n times this question was asked.