Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

How can I use a filehandle indirectly?

by faq_monk (Initiate)
on Oct 08, 1999 at 00:23 UTC ( [id://650] : perlfaq nodetype . print w/replies, xml ) Need Help??

Current Perl documentation can be found at

Here is our local, out-dated (pre-5.6) version:

An indirect filehandle is using something other than a symbol in a place that a filehandle is expected. Here are ways to get those:

    $fh =   SOME_FH;       # bareword is strict-subs hostile
    $fh =  "SOME_FH";      # strict-refs hostile; same package only
    $fh =  *SOME_FH;       # typeglob
    $fh = \*SOME_FH;       # ref to typeglob (bless-able)
    $fh =  *SOME_FH{IO};   # blessed IO::Handle from *SOME_FH typeglob

Or to use the new method from the FileHandle or IO modules to create an anonymous filehandle, store that in a scalar variable, and use it as though it were a normal filehandle.

    use FileHandle;
    $fh = FileHandle->new();

    use IO::Handle;                     # 5.004 or higher
    $fh = IO::Handle->new();

Then use any of those as you would a normal filehandle. Anywhere that Perl is expecting a filehandle, an indirect filehandle may be used instead. An indirect filehandle is just a scalar variable that contains a filehandle. Functions like print, open, seek, or the functions or the <FH> diamond operator will accept either a read filehandle or a scalar variable containing one:

    ($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR);
    print $ofh "Type it: ";
    $got = <$ifh>
    print $efh "What was that: $got";

Of you're passing a filehandle to a function, you can write the function in two ways:

    sub accept_fh {
        my $fh = shift;
        print $fh "Sending to indirect filehandle\n";

Or it can localize a typeglob and use the filehandle directly:

    sub accept_fh {
        local *FH = shift;
        print  FH "Sending to localized filehandle\n";

Both styles work with either objects or typeglobs of real filehandles. (They might also work with strings under some circumstances, but this is risky.)


In the examples above, we assigned the filehandle to a scalar variable before using it. That is because only simple scalar variables, not expressions or subscripts into hashes or arrays, can be used with built-ins like print, printf, or the diamond operator. These are illegal and won't even compile:

    @fd = (*STDIN, *STDOUT, *STDERR);
    print $fd[1] "Type it: ";                           # WRONG
    $got = <$fd[0]>                                     # WRONG
    print $fd[2] "What was that: $got";                 # WRONG

With print and printf, you get around this by using a block and an expression where you would place the filehandle:

    print  { $fd[1] } "funny stuff\n";
    printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559;
    # Pity the poor deadbeef.

That block is a proper block like any other, so you can put more complicated code there. This sends the message out to one of two places:

    $ok = -x "/bin/cat";                
    print { $ok ? $fd[1] : $fd[2] } "cat stat $ok\n";
    print { $fd[ 1+ ($ok || 0) ]  } "cat stat $ok\n";           

This approach of treating print and printf like object methods calls doesn't work for the diamond operator. That's because it's a real operator, not just a function with a comma-less argument. Assuming you've been storing typeglobs in your structure as we did above, you can use the built-in function named readline to reads a record just as <> does. Given the initialization shown above for @fd, this would work, but only because readline() require a typeglob. It doesn't work with objects or strings, which might be a bug we haven't fixed yet.

    $got = readline($fd[0]);

Let it be noted that the flakiness of indirect filehandles is not related to whether they're strings, typeglobs, objects, or anything else. It's the syntax of the fundamental operators. Playing the object game doesn't help you at all here.