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

Hi, I'm having trouble understanding why the following code doesn't work as expected. Any help would be appreciated.
#!/usr/bin/perl my $tf = shift; # any random text file. Say, /etc/passwd open(MF, "< $tf") || die "Unable open $tf for input: $!"; # this doesn't work # my %opt; $opt{'M'} = *MF; while (<$opt{'M'}>) { print "loop one...\n"; } # this doesn't work # my @opt; $opt[0] = *MF; while (<$opt[0]>) { print "loop two...\n"; } # this does work # my $tf = *MF; while (<$tf>) { print "loop three...\n"; }

Replies are listed 'Best First'.
Re: hashs and file handle globs
by broquaint (Abbot) on Nov 20, 2002 at 14:56 UTC
    The problem is that perl is parsing your filehandle iterations as a glob() e.g
    shell> perl -MO=Deparse -e 'open(0); @f=*0; print <$f[0]>' open *0; @f = *0; print CORE::GLOBAL::glob($f[0], 0); -e syntax OK
    You probably want to use the readline() function instead.
    HTH

    _________
    broquaint

      thanks for your help. you are correct that readline() does indeed work. It may be me, but it seems that scalars and hash or array members should be treated the same here? Anyway, I'm grateful it works.
        It may be me, but it seems that scalars and hash or array members should be treated the same here?
        The problem is that perl's globbing syntax looks very similar to it's filehandle access syntax. So anything that looks more complex than a bareword or a scalar is assumed to be a glob. Of course this is where the glob() and readline() functions step in and erase any ambiguity.
        HTH

        _________
        broquaint

Re: (nrd) hashs and file handle globs
by newrisedesigns (Curate) on Nov 20, 2002 at 14:51 UTC

    I'm not sure, but I think it works along the same lines as $_, a scalar that's filled with the line as the while loop iterates over the file. This is just an assumption, but I think you can't stuff into an array or hash slice.

    If you put the following into your code:

    print *MF; print "\n"; print $opt{'M'};

    you'll see that the variables have the same content (unless there's some metadata controlling that), so it appears that the filehandle is being copied into the hash. I think your problem lies in the while loop, but I'm not sure yet why that is.

    Update: from perlsyn:

    The while and until modifiers have the usual "while loop" semantics (conditional evaluated first), except when applied to a do-BLOCK (or to the deprecated do-SUBROUTINE statement), in which case the block executes once before the conditional is evaluated.

    The while is evaluating whether or not the hash or array has something in it. It's not evaluating the fileglob inside.

    John J Reiser
    newrisedesigns.com

Re: hashs and file handle globs
by MarkM (Curate) on Feb 02, 2003 at 08:35 UTC

    The text within <> must be a 'simple scalar variable' in order for it to be interpretted as a reference to a typeglob, and not a shellglob. See the perlop manpage for more information.

    To accomplish what you are trying to do, I recommend using the readline() builtin function that provides the same functionality as <> does:

    my %opt; $opt{'M'} = \*MF; # You should use a reference here. while (readline($opt{'M'})) { print "loop one...\n"; }

    Using readline() allows you to specify an arbitrarily complex expression, while still getting the same behaviour that <> does. For example, readline() also has the behaviour of wrapping an implicit defined($_ = readline(...)) around the readline().