How to redirect STDOUT and STDERR to a variable

17,647

Solution 1

Are you seeking to capture the output in a variable? If so, you have use backticks or qx{} with appropriate redirection. For example, you could use:

#/usr/bin/env perl
use strict;
use warnings;

# Ensure we have a way to write messages
open my $fh, '>', "output" or die;

close(STDOUT);
close(STDERR);

my $out;
open(STDOUT, ">>", \$out) or do { print $fh, "failed to open STDOUT ($!)\n"; die };
open(STDERR, ">>", \$out) or do { print $fh, "failed to open STDERR ($!)\n"; die };

foreach my $i (1..10)
{
    print "print $i\n"; 
    warn "warn $i\n";
    my $extra = qx{make pth$i 2>&1};
    print $fh "<<$i>><<$out>><<$extra>>\n";
}

(I happen to have programs pth1, pth2 and pth3 in the directory - they were made OK; pth4 and above write errors to stderr; the redirection was necessary.)

You should always check the success of operations such as open().

Why is this necessary? Because writing to a variable requires the cooperation of the process doing the writing - and make doesn't know how to cooperate.

Solution 2

use Capture::Tiny!

Solution 3

There are several ways to redirect and restore STDOUT. Some of them work with STDERR too. Here are my two favorites:

Using select:

my $out;
open my $fh, ">>", \$out;
select $fh;
print "written to the variable\n";
select STDOUT;
print "written to original STDOUT\n";

Using local:

my $out
do {
    local *STDOUT;
    open STDOUT, ">>", \$out;
    print "written to the variable\n";
};
print "written to original STDOUT\n";

Enjoy.

Solution 4

The reason this is happening is that the STDOUT and STDERR "filehandles" are not equivalent to stderr and stdout handles provided by the shell to the perl binary. In order to achieve what you want, you should use open instead of system

Solution 5

Why not use IPC::Open3?

Share:
17,647
Deck
Author by

Deck

Updated on June 05, 2022

Comments

  • Deck
    Deck almost 2 years

    I want to redirect STDERR and STDOUT to a variable. I did this.

    close(STDOUT);
    close(STDERR);
    
    my $out;
    open(STDOUT, ">>", \$out);
    open(STDERR, ">>", \$out);
    
    for(1..10)
    {
        print "print\n"; # this is ok. 
        warn "warn\n"; # same
        system("make"); # this is lost. neither in screen nor in variable.
    }
    

    The problem with system. I want the output of this call to be captured too.