If you've ever tried to use a variable for a filehandle, you may well have had some problems. This is just revealing one of the icky places in perl: filehandles aren't first-class citizens the way everything else is, and it really gets in the way sometimes.
Of course, it's just fine to say
$fh = "/some/path"; open($fh, "< $fh"); print $fh "string\n";
But you'll still get into trouble for trying:
$fharray[$i] = "/some/path"; open($fharray[$i], "< $fharray[$i]"); print $fharray[$i] "stuff\n";
You can also do this:
$tmp_fh = $fharray[$i]; print $tmp_fh "stuff\n";
But this is ok:
print { $fharray[$i] } "stuff\n";
There are about four ways of passing in a filehandle. The way everyone tries is just to pass it as a string.
printit(Some_Handle);
Unfortunately, that doesn't work so well, because the package that the printit() function is executing in may in fact not be the one that the handle was opened it:
A simple fix would be to pass it in fully qualified;
printit(main::Some_Handle);
because if you don't, the function is going to have to do some crazy thing like this:
CODE 1:
sub printit { my $fh = shift; my $package = (caller)[0]; $fh =~ s/^[^':]+$/$package::$&/; while (<$fh>) { print; } } A better solution is to pass a typeglob instead:
CODE 2:
printit(*Some_Handle); sub printit { local *FH = shift; while () { print; } }
However, it turns out that you don't have to use a typeglob inside the function. This also works:
CODE 3:
printit(*Some_Handle); sub printit { my $fh = shift; while (<$fh>) { print; } }
As does this even, in case you want to make an object by blessing your reference:
CODE 4:
printit(\*Some_Handle); sub printit { my $fh = shift; while (<$fh>) { print; } }
I used to think that you had to use 1 or preferably 2, but apparently you can get away with number 3 and 4 as well. This is nice because it avoids ever assigning to a typeglob as we do it 2, which is a bit risky.
Some other problems with #1: if you're using strict subs, then you aren't going to be able to do that: the strict subs will gets you. Instead, you'll have to pass in 'main::Some_Handle', but then down in your function, you'll get blown away by strict refs, because you'll be using a string a symbol. So really, the best way is to pass the typeglob (or occasionally a reference to the same).
Other resources at this site: