How to redirect STDOUT to a string?

Discussion in 'Perl Misc' started by J Krugman, May 7, 2004.

  1. J Krugman

    J Krugman Guest

    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

    --
    To s&e^n]d me m~a}i]l r%e*m?o\v[e bit from my a|d)d:r{e:s]s.
    J Krugman, May 7, 2004
    #1
    1. Advertising

  2. J Krugman

    Sam Holden Guest

    On Fri, 7 May 2004 02:31:25 +0000 (UTC),
    J Krugman <> wrote:
    >
    >
    > 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;

    --
    Sam Holden
    Sam Holden, May 7, 2004
    #2
    1. Advertising

  3. J Krugman

    Simon Taylor Guest

    J Krugman wrote:
    > 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
    --
    Unisolve Pty Ltd - Melbourne, Australia
    Simon Taylor, May 7, 2004
    #3
  4. On Fri, 07 May 2004 02:31:25 +0000, J Krugman wrote:

    > 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.
    James Willmore, May 7, 2004
    #4
  5. On Fri, 07 May 2004 00:42:47 -0400, James Willmore wrote:

    > On Fri, 07 May 2004 02:31:25 +0000, J Krugman wrote:


    >> 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:

    [ ... ]

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

    [ ... ]

    > 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.
    James Willmore, May 7, 2004
    #5
  6. In article <c7esdt$l8j$>,
    J Krugman <> wrote:
    >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.
    Mark Jason Dominus, May 7, 2004
    #6
  7. J Krugman <> writes:

    > 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\\
    Brian McCauley, May 7, 2004
    #7
  8. J Krugman

    J Krugman Guest

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

    Thank you!!!

    In <> Brian McCauley <> writes:

    >J Krugman <> writes:


    >> 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.


    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.)

    >> I want to capture the output of these subs in a Perl string instead.


    >[ 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

    --
    To s&e^n]d me m~a}i]l r%e*m?o\v[e bit from my a|d)d:r{e:s]s.
    J Krugman, May 7, 2004
    #8
  9. In article <c7g56k$37c$>,
    J Krugman <> wrote:

    > 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

    --
    Pukku
    Richard Morse, May 7, 2004
    #9
  10. J Krugman

    Ben Morrow Guest

    Quoth J Krugman <>:
    > 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

    --
    For the last month, a large number of PSNs in the Arpa[Inter-]net have been
    reporting symptoms of congestion ... These reports have been accompanied by an
    increasing number of user complaints ... As of June,... the Arpanet contained
    47 nodes and 63 links. [ftp://rtfm.mit.edu/pub/arpaprob.txt] *
    Ben Morrow, May 7, 2004
    #10
  11. J Krugman wrote:
    >
    > 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
    --
    use Perl;
    program
    fulfillment
    John W. Krahn, May 8, 2004
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. VisionSet
    Replies:
    6
    Views:
    9,616
    Sudsy
    Sep 20, 2003
  2. Elad
    Replies:
    0
    Views:
    404
  3. Sal
    Replies:
    1
    Views:
    381
  4. Andreas S
    Replies:
    3
    Views:
    247
    Eric Hodel
    Dec 9, 2006
  5. Replies:
    2
    Views:
    320
    A. Sinan Unur
    Dec 7, 2005
Loading...

Share This Page