mnj200g has asked for the wisdom of the Perl Monks concerning the following question:

Hi. I am a beginner and need some PERL help. I am testing a function that I cannot change. I need to capture the print statements from this funtion. For example, the following function: sub_I_can't_change($$$) { code code print "line 1\n"; print "line 2\n"; return code; } How do I capture the outputs that it prints to the screen. I would prefer to capture the data into a variable if possible. Thanks. MNJ
  • Comment on Need Help: Capture Print Outputs from a Function

Replies are listed 'Best First'.
Re: Need Help: Capture Print Outputs from a Function
by BrowserUk (Patriarch) on May 02, 2006 at 17:34 UTC

    Here's one way

    #! perl -sw use strict; sub immutable { print "immutable received args: [ @_ ]\n"; print "Some more stuff\n"; } ## Save a copy of STDOUT open SAVED, '>&=STDOUT'; close STDOUT; ## Open STDOUT to a variable (ramfile)(Requires 5.8.x) open STDOUT, '>', \ my( $var ) or die $!; ## Call the sub immutable( qw[ some args here ] ); ## Close the ramfile close STDOUT; ## Redirect STDOUT back to it's original place open STDOUT, '>&=SAVED' or die $!; ## Discard the backup close SAVED; ## Use the captured output print "The variable \$var now contains:\n'$var'\n"; __END__ C:\test>junk2 The variable $var now contains: 'immutable received args: [ some args here ] Some more stuff '

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      That's a lot of work to avoid using select.

        True, but it is guarenteed to work even if someone uses print STDOUT stuff;, when select won't.

        The case of that where I got bitten is when you pass \*STDOUT to some module and internally it uses

        printf { $self->{fh} } "%s\n", 'stuff';

        Which is not a completely uncommon scenario.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        I prefer

        { open local *STDOUT, '>', \$buf; ... }
        over
        open TEMP, '>', \$buf; my $old_select = select(TEMP); ... select($old_select);

        since the former restores STDOUT even in the case of exceptions. The former, however, doesn't work if someone has previously called select. I guess the comprehensive solution would be:

        { my $old_select = select(); my $handle = on_release { select($old_select); }; open local *STDOUT, '>', \$buf; select(STDOUT); ... }

        It even handles exceptions thrown by signal handlers.

        Updated.

Re: Need Help: Capture Print Outputs from a Function
by wfsp (Abbot) on May 02, 2006 at 17:35 UTC
    I found this by doing a supersearch.
    #!/usr/bin/perl use strict; use warnings; my ($buf); { local *STDOUT; open( STDOUT, '>', \$buf ) or die "Write to buffer failed\n"; mysub(); } print "buffer: $buf\n"; sub mysub{ print "mysub output\n"; }
    Output:
    ---------- Capture Output ---------- > "C:\Perl\bin\perl.exe" _new.pl buffer: mysub output > Terminated with exit code 0.
    Does that help?

    Update: The above requires 5.8 (thanks to ikegami for pointing that out).

      It does not seem to be working. I get the following message: Use of uninitialized value in concatenation (.) or string at scop/x.pl line 126. buffer: Line 126 is where print "buffer: $buf\n"; is. Also, what is the structure under my ($buf); in your code? Is that how PERL creates a macro or what C calls prototypes? I've also tried the first method mentioned above and that also fail to initialize the variable $var. In that first function, what is the significant of "qw"? Thanks.
        I get the following message: Use of uninitialized value in concatenation (.)

        You're using a version of Perl older than 5.8.0, when open(STDOUT, '>', \$buf) was introduced. Before 5.8, \$buf would be stringified to something like SCALAR(0x1ab2760). The output ends up in a file by that name instead of going to $buf, so $buf is still undefined when you go to inspect it.

        Before 5.8, you had to use IO::String or IO::Scalar.

        Also, what is the structure under my ($buf); in your code?

        It creates a new scope. This causes local *STDOUT; to be undone (thus restoring the original STDOUT) before the last print.

        what is the significant of "qw"

        qw[ some args here ]
        is the same thing as
        ('some', 'args', 'here')
        See perlop.

        I updated my node to point out that perl 5.8 is required for that to work (apologies for the delay).

        Which version of perl are you using?

      Thank you again to everyone. It is working. I did ran into the problem mentioned by BrowserUK where another function using select(STDOUT) and then setting "$| = 1;" (no buffering). That gave me the problem of $buf coming back empty.

      I fixed that by setting buffer on ($| = 0) just before the local "scope".

      Again, thank you.

      MNJ