How to redirect STDOUT and STDERR to a variable
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
?
Deck
Updated on June 05, 2022Comments
-
Deck almost 2 years
I want to redirect
STDERR
andSTDOUT
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.