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

I have been successfully reading files in a function for quite some time (see sample code snippet "WORKS" below). I am working on changing how I read the arguments that come into my function so that it is easier for other people to use. I tried changing to the use of a hash (see snippet "FAILS" below), but instead of getting the contents of the file that I opened, I get the glob address, e.g. GLOB(0x1499a8). I feel like the answer is right in front of me, but I still cannot see it. Can anyone help?
WORKS
#!/usr/bin/perl my $handle1; open($handle1, "< /tmp/1") || die "Input file does not exist.\n"; # Case 1 GetFileContentsViaScalar(\*$handle1); close($handle1); sub GetFileContentsViaScalar { my $FH = shift; print "SHIFT:\n"; { local($/); print <$FH>; } }
FAILS
#!/usr/bin/perl my $handle1; open($handle1, "< /tmp/1") || die "Input file does not exist.\n"; # Case 2 -- fails GetFileContentsViaFnHash(\*$handle1); close($handle1); sub GetFileContentsViaFnHash { my %test; $test{FH} = shift; print "Function hash:\n"; { local($/); print <$test{FH}>; } }

Replies are listed 'Best First'.
Re: Getting file handle glob name instead of contents
by TGI (Parson) on Sep 10, 2008 at 18:08 UTC

    Why are you passing typeglobs? There's no reason to use typeglobs here, just pass the lexical handle as a scalar. Plenty of older tutorials say to pass filehandles as globs, but that only applies to global filehandles generated when you do stuff like: open( FOO, ">/bar/baz" ). It's best to use a 3 argument version of open and a lexical handle.

    #!/usr/bin/perl open(my $handle1, "<", "/tmp/1") or die "Input file does not exist.\n" +; # Case 2 -- fails GetFileContents($handle1); close($handle1); sub GetFileContents { my $foo = shift; print "Function hash:\n"; { local($/); print <$foo>; } }

    On a side note, I like to use the lower precedence or for error detection, becuase it won't mess with my lists if I leave off parens. See perlop section on C-Style Logical Or for more info.

    Update: Clarified globs vs typeglobs. Also, it's worth pointing out that using a lexical handle and not a typeglob doesn't resolve the issue with the <$hash{lexical_handle}> construct. Others have covered that issue.


    TGI says moo

      My apologies to all for not RTFM (or more precisely, not finding the relevant section to read). TGI, thanks for your additional remarks concerning passing scalars. I don't use global file handles any more, so passing just the scalar will work perfectly.
Re: Getting file handle glob name instead of contents
by Fletch (Bishop) on Sep 10, 2008 at 17:36 UTC

    Quoth perlop:

    If what's within the angle brackets is neither a filehandle nor a simple scalar variable containing a filehandle name, typeglob, or typeglob reference, it is interpreted as a filename pattern to be globbed, and either a list of filenames or the next filename in the list is returned, depending on context. This distinction is determined on syntactic grounds alone. That means "<$x>" is always a readline() from an indirect handle, but "<$hash{key}>" is always a glob(). That's because $x is a simple scalar variable, but $hash{key} is not--it's a hash element. Even "<$x >" (note the extra space) is treated as "glob("$x ")", not "readline($x)".

    Your $test{FH} isn't a simple scalar variable so it's interpreted as a glob pattern.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Getting file handle glob name instead of contents
by Tanktalus (Canon) on Sep 10, 2008 at 17:41 UTC

    The evil <> operator which tries to figure out if it's dealing with a filehandle or a glob operation ... you'll want to take a look at perlop for more details of how perl figures this out:

    If what’s within the angle brackets is neither a filehandle nor + a sim&#8208; ple scalar variable containing a filehandle name, typeglob, or +typeglob reference, it is interpreted as a filename pattern to be globbe +d, and either a list of filenames or the next filename in the list is returned, depending on context. This distinction is determined + on syn&#8208; tactic grounds alone. That means "<$x>" is always a readline() + from an indirect handle, but "<$hash{key}>" is always a glob(). That’s + because $x is a simple scalar variable, but $hash{key} is not--it’s a h +ash ele&#8208; ment. Even "<$x >" (note the extra space) is treated as "glob( +"$x ")", not "readline($x)".
    You'll want to either do:
    my $fh = $test{FH}; print <$fh>;
    or you'll want to:
    use IO::Handle; print $test{FH}->getlines();
    Hope that helps,