Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Passing filehandles to subroutines

by ibanix (Hermit)
on Jan 27, 2003 at 04:38 UTC ( [id://230116]=perlquestion: print w/replies, xml ) Need Help??

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

Hi monks,

This shouldn't be too hard to answer. How do I safely pass a filehandle into a subroutine? Let's say I've got code like this:
use strict; use warnings; my($infile, $outfile) = @ARGV; open(IN, "$infile"); open(OUT, ">$outfile"); { blah } print_some_stuff(); sub print_some_stuff { print OUT <<"EOF"; This is a test, it is only a test. In the event of an emergency, run around in a panic. EOF }
Leaving the other details out, if I wanted to print out to different files, I have re-open OUT to different files. If I could pass my filehandle to print_some_stuff, I could print to a number of files at the same time.

Thanks!

ibanix

$ echo '$0 & $0 &' > foo; chmod a+x foo; foo;

Replies are listed 'Best First'.
Re: Passing filehandles to subroutines
by Paladin (Vicar) on Jan 27, 2003 at 04:50 UTC
    Take a look at IO::File.
    my $handle = new IO::File "> $outfile"; print_stuff_to($handle); sub print_stuff_to { my $fh = shift; print $fh "Foo Bar"; }
Re: Passing filehandles to subroutines
by John M. Dlugosz (Monsignor) on Jan 27, 2003 at 06:53 UTC
    I never use global file-handle identifiers any more. Without pulling in the whole File::IO module, you can still do this:

    open (my $in, $infile) or die; foo ($in); sub foo { my $file= shift; print $file "Some Stuff."; # note no comma }
    Basically, a reference to a glob can be used just like a glob to mean the associated file handle. In Perl 5.6 I think the open function will auto-vivify to just that, so you don't need to use a module or tricks to create a reference to an anonomous glob anymore. There's been discussions on that here; I posted a question concerning using this as the prefered method moving forward, when I heard about the auto-vivification.

    —John

      John,

      This is very cool. I like this method. Do you have any idea if this is going to be supported in Perl 6? Or, perhaps I should ask, is this 'kosher'? This isn't a "may be removed if we feel like it" feature, is it?

      Thanks!

      ibanix

      $ echo '$0 & $0 &' > foo; chmod a+x foo; foo;
        See if you can find my thread via super search or skimming the list of nodes I posted. That is when I asked if it was 'kosher' and got a lot of remarks about it. What I remember: yes, it is proper and will work moving forward, but doesn't work on older versions (I don't remember when) so it is an issue if you need to run on older stuff, but no other issues impressed me enough to remember or disuade me.

        —John

        It's pretty normal as far as I know, I use it all the time. Look at the perlsub documentation about passing around filehandles.

        C.

Re: Passing filehandles to subroutines
by BrowserUk (Patriarch) on Jan 27, 2003 at 05:32 UTC

    Besides IO::File which probably has other advantages, you can also pass globs by prefixing the name with *. Eg.

    sub myprint { my $fh = shift; print $fh $_[0]; } ... open OUT, '>', 'junk' or die $!; myprint *OUT, 'test'; close OUT; c:\test>type junk test c:\test>

    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Re: Passing filehandles to subroutines
by tall_man (Parson) on Jan 27, 2003 at 05:46 UTC
    I think IO::File is the best way to go, but there is another way if you really don't want to change your "OUT" style filehandles in the main code. You can pass references to typeglobs into subroutines, like this:
    print_some_stuff(\*OUT); sub print_some_stuff { my $fh = shift; print $fh "stuff\n"; }
Re: Passing filehandles to subroutines
by Aristotle (Chancellor) on Jan 27, 2003 at 11:41 UTC
    As already mentioned, on Perl 5.6+ you can simply
    open my $fh, "<", $filename;
    and then pass $fh around. If you want to be compatible with earlier versions, it is only slightly more verbose:
    use Symbol qw(gensym); # ... open +(my $fh = gensym), "<$filename";
    And yes, this is definitely going to stay with us in Perl 5. In Perl 6 you'll be doing things entirely differently:
    my $fh = open "<", $filename;
    Though the other syntax will probably remain supported. Still I'm definitely switching to this new construct as soon as possible.

    Makeshifts last the longest.

Re: Passing filehandles to subroutines
by rdfield (Priest) on Jan 27, 2003 at 10:08 UTC
    I know this isn't strictly answering the question, but after a lot of pondering I came to the conslusion that removing the filehandle from the print, and selecting the correct filehandle increased the functionality of my code dramatically.

    For instance, say I have a function that generates HTML, I can (a) use it 'vanilla' style under a webserver and get a webpage, (b) tie a filehandle to a scalar, select it and manipulate the resultant HTML programmatically, or (c) select a normal filehandle for placement into a content management hierarchy (or whatever). Same function, different results.

    rdfield

      I'd prefer to keep an explicit filehandle on my prints and default it as in $fh ||= \*STDOUT or something like that. I still get all of the functionality you mention and without having to mess with a global variable (ie the "selected filehandle").

      Makeshifts last the longest.

        I knew I'd come up with a concrete counter-example eventually :)

        I use Pod::HTML in a mod_perl handler to generate "Help" screens on the fly when a user clicks on the Help menu item in my CGI application. The module uses a named filehandle, which when used in "interactive" mode is opened against "". Works great from the command line - but completely baulks under mod_perl. Back to the drawing board: I worked around it by supplying it with a temporary (session based) file name, and then reading the resultant file and printing it to (what appears to be) STDOUT.

        rdfield

Re: Passing filehandles to subroutines
by artist (Parson) on Jan 27, 2003 at 15:39 UTC
    Based on various suggestion received here, here is the tested code.
    use strict; use warnings; my $outfile = "test.txt"; open (my $ofh, ">$outfile") or die; foo ($ofh); #Prints to the file pointed by $ofh foo(); #Prints to STDOUT sub foo { my $filehandle= shift; $filehandle ||= \*STDOUT ; select($filehandle); print <<"EOF"; This is a test, it is only a test. In the event of an emergency, run around in a panic. EOF }
    artist

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2024-03-29 11:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found