Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Redirect Subroutine Output

by spickles (Scribe)
on Aug 26, 2009 at 15:41 UTC ( #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

Comment on Redirect Subroutine Output
Download Code
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 (Pope) 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
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? | Other CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2014-10-01 00:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (386 votes), past polls