How to redirect STDOUT to a string?

J

J Krugman

I'm using a module whose subs all write to STDOUT. I want to
capture the output of these subs in a Perl string instead. My
boneheaded (i.e. failed) attempt to solve this problem was:

use IO::Scalar;
my $string;
*HOLD = *STDOUT;
$STRING = IO::Scalar->new(\$string);
*STDOUT = *STRING;
foo(); # prints to STDOUT; output should be in $string ???
*STDOUT = *HOLD;

What's the correct way to do what I want to do?

Thanks!

jill
 
S

Sam Holden

I'm using a module whose subs all write to STDOUT. I want to
capture the output of these subs in a Perl string instead. My
boneheaded (i.e. failed) attempt to solve this problem was:

use IO::Scalar;
my $string;
*HOLD = *STDOUT;
$STRING = IO::Scalar->new(\$string);
*STDOUT = *STRING;
foo(); # prints to STDOUT; output should be in $string ???
*STDOUT = *HOLD;

What's the correct way to do what I want to do?

perldoc IO::Scalar :

use IO::Scalar;
### Writing to a scalar...
my $s;
tie *OUT, 'IO::Scalar', \$s;
print OUT "line 1\nline 2\n", "line 3\n";
print "String is now: $s\n"

So something like:

use IO::Scalar;
my $string;
tie *OUT, 'IO::Scalar', \$string;
*HOLD = *STDOUT;
*STDOUT = *OUT;
foo(); # prints to STDOUT; output should be in $string ???
*STDOUT = *HOLD;
 
S

Simon Taylor

J said:
I'm using a module whose subs all write to STDOUT. I want to
capture the output of these subs in a Perl string instead. My
boneheaded (i.e. failed) attempt to solve this problem was:

use IO::Scalar;
my $string;
*HOLD = *STDOUT;
$STRING = IO::Scalar->new(\$string);
*STDOUT = *STRING;
foo(); # prints to STDOUT; output should be in $string ???
*STDOUT = *HOLD;

What's the correct way to do what I want to do?

Hi Jill,

I've seen the Filter::Handle module used for this purpose, but I should
warn you that I couldn't get it to compile just now in my perl 5.8.3
Linux environment when I downloaded it from CPAN

In any event, it's probably worth a look.

Regards,

Simon
 
J

James Willmore

I'm using a module whose subs all write to STDOUT. I want to capture
the output of these subs in a Perl string instead. My boneheaded (i.e.
failed) attempt to solve this problem was:

use IO::Scalar;
my $string;
*HOLD = *STDOUT;
$STRING = IO::Scalar->new(\$string);
*STDOUT = *STRING;
foo(); # prints to STDOUT; output should be in $string ??? *STDOUT =
*HOLD;

What's the correct way to do what I want to do?

Try doing the following:

#duplicate STDOUT to a filehandle - so we can restore #STDOUT later
open(MYOUT, ">&STDOUT")
or die "Can't dup STDOUT: $!\n";
#open a file to hold STDOUT
open(STDOUT, ">some_log_file")
or die "Can't open STDOUT log file: $!\n";
#do some printing to STDOUT
print "STDOUT is now going into the log file\n";
....
#restore STDOUT
open(STDOUT, ">&MYOUT")
or die "Can't restore STDOUT: $!\n";

The above code will work if you just want to redirect STDOUT to a file.
Simple, yet effective :)

HTH

--
Jim

Copyright notice: all code written by the author in this post is
released under the GPL. http://www.gnu.org/licenses/gpl.txt
for more information.

a fortune quote ...
Hofstadter's Law: It always takes longer than you expect, even
when you take Hofstadter's Law into account.
 
J

James Willmore

[ ... ]
[ ... ]
The above code will work if you just want to redirect STDOUT to a file.

My bad - you wanted a scalar and I gave a file :-(

Maybe you can use the code in the future :)

--
Jim

Copyright notice: all code written by the author in this post is
released under the GPL. http://www.gnu.org/licenses/gpl.txt
for more information.

a fortune quote ...
Blessed are they who Go Around in Circles, for they Shall be
Known as Wheels.
 
M

Mark Jason Dominus

I'm using a module whose subs all write to STDOUT. I want to
capture the output of these subs in a Perl string instead.

sub X::TIEHANDLE { my ($c, $r) = @_; bless $r => $c }
sub X::pRINT { my $r = shift; $$r .= join "", @_ }
tie *STDOUT => "X", \$OUTPUT;

and now everything printed to STDOUT will appear in $OUTPUT.

Use

untie *STDOUT;

to turn it off.
 
B

Brian McCauley

J Krugman said:
I'm using a module whose subs all write to STDOUT.

Are you sure?

It would be far more normal for them to write to the currently
selected output handle which need not be STDOUT.
I want to capture the output of these subs in a Perl string instead.

[ snip - almost correct munging of *STDOUT using IO::Scalar ]
What's the correct way to do what I want to do?

If they do explicitly write to STDOUT then you can mung *STDOUT as
discussed elsewhere in this thread. If not, then you can simply
change the currently selected output handle with select().

Note: in Perl 5.8 the functionality of IO::Scalar is available
using open().

require 5.8.0;
open my $string_handle, '>', \my $string or die $!;
my $save_selection = select $string_handle;
foo(); # prints to current output; output will be in $string
select($save_selection);

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
J

J Krugman

Wow! I've learned so much from all of your replies!

Thank you!!!

Are you sure?
It would be far more normal for them to write to the currently
selected output handle which need not be STDOUT.

You're 100% right. I totally goofed there when I wrote "write to
STDOUT". The module in question just uses print without an explicit
filehandle argument, which, as you say, doesn't imply that the
output will necessarily go to STDOUT.

One related question: is there a way to get the currently selected
filehandle without using select (and therefore deselecting it)? (I
thought that this would be stuck in some Perl variable, but I can't
find it in the perlvar manpage.)

And one more: can someone point me to where in the Perl documentation
lexical filehandles are discussed? I'm sure it's in there somewhere,
but after a lot of page-flipping and poring over my Camel book's
index, I still can't find anything. (My immediate interest is
confirming my guess that "close" is called automatically on such
handles when they go out of scope, but in general I want to get
the full official lowdown on lexical handles.)
[ snip - almost correct munging of *STDOUT using IO::Scalar ]

I still don't understand why it didn't work... If anyone cares to
throw me another cluebrick, here's the failed strategy again, for
easy reference:

use IO::Scalar;
my $string;
*HOLD = *STDOUT;
$STRING = IO::Scalar->new(\$string);
*STDOUT = *STRING;
foo(); # prints to STDOUT; output should be in $string ???
*STDOUT = *HOLD;

TIA,

jill
 
R

Richard Morse

J Krugman said:
And one more: can someone point me to where in the Perl documentation
lexical filehandles are discussed? I'm sure it's in there somewhere,
but after a lot of page-flipping and poring over my Camel book's
index, I still can't find anything. (My immediate interest is
confirming my guess that "close" is called automatically on such
handles when they go out of scope, but in general I want to get
the full official lowdown on lexical handles.)

Well, in the 3rd edition of the Camel Book, on page 748, it says:

=begin quote

But C<open> is special in that if you supply it with an undefined
variable for the indirect filehandle, Perl will automatically define
that variable for you, that is, autovivifying it to contain a proper
filehandle reference. One advantage of this is that the filehandle will
be closed automatically when there are no further refences to it,
typically when the variable goes out of scope:

{
my $fh; # (uninitialized)
open($fh, ">logfile") # $fh is autovivified
or die "Can't create logfile: $!";
... # do stuff with $fh
} # $fh closed here

The C<my $fh> declaration can be readably incorporated into the C<open>:

open my $fh, ">logfile" or die ...

=end quote

=cut

Also, on the topic that you were originally asking about, while looking
through `perldoc -f open` for Perl 5.8.1 (Mac OS X 10.3.3), I noticed
the following:

=begin quote

File handles can be opened to "in memory" files held in Perl scalars
via:

open($fh, '>', \$variable) || ..

Though if you try to re-open "STDOUT" or "STDERR" as an "in memory"
file, you have to close it first:

close STDOUT;
open STDOUT, '>', \$variable or die "Can't open STDOUT: $!";

=end quote

=cut

HTH,
Ricky
 
B

Ben Morrow

Quoth J Krugman said:
One related question: is there a way to get the currently selected
filehandle without using select (and therefore deselecting it)? (I
thought that this would be stuck in some Perl variable, but I can't
find it in the perlvar manpage.)

Howabout

my $FH = select STDOUT;
select $FH;

? Unselecting and then reselecting a FH has no effect (you do need to be
sure that STDOUT will be open though, which *ought* to always be
safe...).

Ben
 
J

John W. Krahn

J said:
One related question: is there a way to get the currently selected
filehandle without using select (and therefore deselecting it)? (I
thought that this would be stuck in some Perl variable, but I can't
find it in the perlvar manpage.)

select with no arguments will return the currently selected filehandle.

use POSIX qw( STDOUT_FILENO );

if ( STDOUT_FILENO == fileno( select ) ) {
print "The current default filehandle is STDOUT.\n";
}

And one more: can someone point me to where in the Perl documentation
lexical filehandles are discussed?

In perldata under the "Typeglobs and Filehandles" section.

perldoc perldata



John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top