tags:

views:

90

answers:

4

I am calling a function that writes to STDOUT using print. How can I capture this in a variable?

Note that all this happens within the same process

A: 

You can make use of open for this as:

close STDOUT;
open STDOUT, '>', \$variable or die "Can't open STDOUT: $!";
codaddict
You probably don't want to do this. There's a lot of other stuff you have to add around this code to ensure that you don't disturb other parts of the program that need the real standard out.
brian d foy
A: 

See http://www.perlmonks.org/?node_id=11007

Oops, above is for redirecting stdout to a file, not to a variable.

It may be cleaner code to have your print statements use a file handle other than STDOUT since redirecting STDOUT is not what a person expects.

Eg

open MEM, '>', \$variable or die "Can't open MEM: $!";
print MEM $stuff;  # note, no comma between filehandle and the print list
Larry K
+3  A: 

If the code in question is not using STDOUT explicitly (i.e., it just does print "..."), you can use select to change the filehandle that print uses:

my $output;
open(my $outputFH, '>', \$output) or die; # This shouldn't fail
my $oldFH = select $outputFH;
call_code_that_prints();
select $oldFH;
close $outputFH;

print $output;    # Here's what we collected

Using select makes it easier to restore STDOUT afterward. Closing and reopening STDOUT is harder to undo. Note that select does not affect STDOUT itself, so it doesn't affect external processes, but you said you didn't have any. It also doesn't affect code that does something like print STDOUT "...".

If the select method isn't sufficient for your needs, I'd recommend you try Capture::Tiny. It can capture output from external programs and code that writes to STDOUT explicitly. But it can't (currently) capture only STDOUT; it always captures both STDOUT and STDERR (either separately or merged into one string).

cjm
+5  A: 

The new, cool way to handle this is with Capture::Tiny. You can use it surgically to affect just the part of the program where you need it without disturbing anything else.

brian d foy
One problem with using Capture::Tiny for this is that it has no way to capture only STDOUT and leave STDERR alone. It always captures both, either separately or merged.
cjm
Well, not until somebody submits a patch. [RT #60515](https://rt.cpan.org/Ticket/Display.html?id=60515):)
brian d foy