Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Redirect Subroutine Output

by spickles (Scribe)
on Aug 26, 2009 at 15:41 UTC ( [id://791373]=perlquestion: print w/replies, xml ) Need Help??

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

Monks -

I wrote a subroutine to write some commands to the screen for a user to verify the output. If the user selects 'YES' to then process those commands, they'll be delivered to a switch via telnet. So the first time through the subroutine I print to the screen. How can I make my code efficient to use the same subroutine again but this time print to a file? To print to the screen I just neeed to call 'print "blah\n";', but to print to a file I need 'print MYFILE "blah\n";'. I could pass a variable to the subroutine and say something like

if ($to_file == 0) { print "blah\n"; } else { print MYFILE "blah\n"; }

Again, I'm trying to find a way to perform this efficiently so I don't have to write these if statements and lines more than once to make efficient code. Can I call the subroutine normally the first time to print to the screen, and call it a second time with a pipe or redirect to have those print functions go to a file?

Regards,

Scott

Replies are listed 'Best First'.
Re: Redirect Subroutine Output
by goeb (Pilgrim) on Aug 26, 2009 at 15:54 UTC
    You could write the sub the following way:
    use warnings; use strict; sub print_to { print {$_[0]} $_[1]; } print_to (*STDOUT, "test stdout"); print_to (*STDERR, "test stderr");
      goeb -

      Why do I get the error 'scalar found where operator expected' if I omit the braces around the $_[0]? What are the braces doing and why aren't they required around the second element?

      Regards,
      Scott
        From the docs for print:
        Note that if you're storing FILEHANDLEs in an array, or if you're using any other expression more complex than a scalar variable to retrieve it, you will have to use a block returning the filehandle value instead:
        I believe the braces define a block of code, and I believe $_[0] qualifies as an 'expression more complex than a scalar variable'. If you refactor the sub like this, then the braces around the FILEHANDLE are not needed:
        use warnings; use strict; sub print_to { my ($fh, $str) = @_; print $fh $str; } print_to (*STDOUT, "test stdout"); print_to (*STDERR, "test stderr");
Re: Redirect Subroutine Output
by ambrus (Abbot) on Aug 26, 2009 at 16:11 UTC

    I recommend one of the following. (All the code below are UNTESTED and may contain errors.)

    • If the output data is short, just collect it to a string, eg.
      sub foo { my $o = ""; $o .= "blah\n"; $o; } if ($to_file == 0) { print foo(); } else { print MYFILE foo(); }
    • Use the default filehandle you select, eg.
      sub foo { print "blah\n"; } my $OLDH; if ($to_file) { $OLDH = select MYFILE; } foo(); $OLDH and select $OLDH;
    • Pass a filehandle as an argument to the function and print to that, eg.
      sub foo { my($O) = @_; print $O "blah\n"; } foo($to_file ? *MYFILE : *STDOUT);
    • Pass a callback sub as an argument to the function that's called for each line.
      sub foo { my($P) = @_; &$P("blah\n"); } foo($to_file ? sub { print MYFILE @_ } : sub { print @_ }); # or foo(sub { if ($to_file) { print MYFILE @_ } else { print @_ } });
    • Same as above but with a global variable or global sub instead of argument, eg one of.
      our $O; sub foo { print $O "blah\n"; } $O = $to_file ? *MYFILE : *STDOUT; foo(); # OR sub foo { print O "blah\n"; } *O = $to_file ? *MYFILE{IO} : *STDOUT{IO}; # (the {IO} is not strictly needed but this way we avoid overwriting $ +O etc) foo(); # or same as above but like open O, ">&=", ($to_file ? *MYFILE : *STDOUT); # or you could even use *MYFILE instead of *O # OR sub foo { my($P) = @_; pri("blah\n"); } sub pri { if ($to_file) { print MYFILE @_ } else { print @_ } }
Re: Redirect Subroutine Output
by ikegami (Patriarch) on Aug 26, 2009 at 17:06 UTC
    Better solution:
    my $out_fh; if ($to_file) { open($out_fh, '>', ...) or die(...); } else { $out_fh = \*STDOUT; } ... print $out_fh "blah\n";

    You can also change the default handle:

    if ($to_file) { open(my $out_fh, '>', ...) or die(...); select($out_fh); } ... print "blah\n";
      This is why I LOVE this website...so many options! Thanks to everyone that responded. The quickest and most direct route for me is to store to a concatenated string and then print that string to either STDOUT or MYFILE depending on how I call a print function.

        print that string to either STDOUT or MYFILE depending on how I call a print function.

        print { $to_file ? *MYFILE : *STDOUT } $str;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://791373]
Approved by perl_devel
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (7)
As of 2024-04-16 11:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found