Reputation: 1979
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.
Upvotes: 16
Views: 20450
Reputation: 3198
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.
Upvotes: 6
Reputation: 20948
If you want STDOUT
(from print()
s) and STDERR
(from warn()
s) to be merged, then use...
my ($merged, @result) = capture_merged { print "Hello, world!" }; # static code
my ($merged, @result) = capture_merged { eval $codetoeval }; # code in variable
If you want them separated...
my ($stdout, $stderr, @result) = capture { print "Hello, world!" }; # static code
my ($stdout, $stderr, @result) = capture { eval $codetoeval }; # code in variable
@result
indicates the success, with success being [1]
, and failure being []
. Tiny has a ton of other functions that you can look through for other cases, like code references, etc.. But I think the code above should cover most of any Perl developer's needs.
Upvotes: 1
Reputation: 754920
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.
Upvotes: 6