Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

globbing filehandles in arrays

by why_bird (Pilgrim)
on Jan 23, 2009 at 13:22 UTC ( [id://738473]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks

I'm struggling a little with typeglobbing and filehandles. I've read this excellent node and more besides

What I can't figure out is why does this NOT work:

#assume files a.txt and b.txt exist and are normal, readable files. use strict; use warnings; open(FILE_A,"<","a.txt") || die "Could not open file 'a.txt': $!\n"; open(FILE_B,"<","b.txt") || die "Could not open file 'b.txt': $!\n"; my @FH=(*FILE_A,*FILE_B); for(my $i=0;$i<2;$i++){ while(my $line=<$FH[$i]>){ print "line: $line\n"; } } exit(0);
(And it also doesn't work if you try any of the following:
  • *FILE_A    -> \*FILE_A
  • $FH[$i]    -> *$FH[$i]
  • $FH[$i]    -> ${FH[$i]}
  • *FILE_A    -> \*FILE_A && $FH[$i] -> *$FH[$i]
etc.. the point being I've tried quite a few things. Specifically the problem is that File::glob::csh_glob returns undef, except when you do
  • *FILE_A -> \*FILE_A
when it returns "GLOB(0x52f9f0)" (obv memory address changes..), but then the output is line: GLOB(0x52f9f0)

However, this works!!

#...as before... for(my $i=0;$i<2;$i++){ my $fh=$FH[$i]; # <----** while(my $line=<$fh>){ #...as before...
And it still works whether
  • *FILE_A --> \*FILE_A
or not...

Why? What's the difference? Am I missing something fundamental here? Or is this some kind of 'feature'? Or is the first syntax ambiguous, or.. what??

Cheers
why_bird

edit: Formatting issues!

edit: ">" to "<", thanks Fletch

........
Those are my principles. If you don't like them I have others.
-- Groucho Marx
.......

Replies are listed 'Best First'.
Re: globbing filehandles in arrays
by almut (Canon) on Jan 23, 2009 at 13:44 UTC
    while(my $line=<$FH[$i]>){

    <$FH[$i]> doesn't work for syntactic reasons, i.e. special parsing rules apply for <...>, and only simple expressions like <$fh> can be handled.

    Use readline $FH[$i] instead, if you don't want to use an intermediate variable.

    Update: also note that whitespace isn't allowed either, i.e. < $fh > and <$ fh> won't work... it has to be exactly <$fh>.

      Ah, I didn't know that (either about readline or about special parsing rules for <...>).

      Thanks!
      why_bird
      ........
      Those are my principles. If you don't like them I have others.
      -- Groucho Marx
      .......
Re: globbing filehandles in arrays
by ikegami (Patriarch) on Jan 23, 2009 at 13:50 UTC

    <> is two different operators. Based on its operand, it's an alias for readline or it's an alias for glob. Here are two ways of forcing readline:

    while (my $line = readline($FH[$i])) { ... }
    my $fh = $FH[$i]; while (my $line = <$fh>) { ... }

    There's still the question of why you are using global variables for no reason.

    open(FILE_A,">","a.txt") || ...; open(FILE_B,">","b.txt") || ...; my @FH=(*FILE_A,*FILE_B);

    should be

    open(my $FILE_A,">","a.txt") || ...; open(my $FILE_B,">","b.txt") || ...; my @FH=($FILE_A,$FILE_B);

    You're using 3-arg open which was introduced at the same time as lexical file handles, so it's not a backwards compatibility issue.

      Or perhaps:

      my @FH; for my $file ( qw/a.txt b.txt/ ) { open( $FH[ @FH ], '>', $file ) || ...; }
      You're using 3-arg open which was introduced at the same time as lexical file handles, so it's not a backwards compatibility issue.

      Wow, I have to say I'm surprised that I really didn't know about something as basic as that!! Just goes to show what perlmonks can teach you. Strange also because I've found the global non-lexical file handles a real pain in the past and have never realised you could do it like that. I consider myself well and truly corrected (and pleased!)

      For future reference, here is the (most?) relevent perldoc documentation, which strangely I hadn't come across (or perhaps rather read thoroughly) before. Also, perlopentut says the above explicitly, which I notice now that I come to look for it!

      It still seems to be true though that the vast majority of examples in open and perlopentut are given using those old global filehandles, which I find a bit strange if it's not 'recommended' behaviour (I would certainly not recommend it!). Is this just because the documentation is old, or is there another reason?

      Thanks
      why_bird
      ........
      Those are my principles. If you don't like them I have others.
      -- Groucho Marx
      .......

        Probably just because noone got around to doing it ...until recently. It's finally been fixed in bleed (5.12 to be) and backported to maint-5.10 (5.10.1 to be).

        There's still lots of example with non-lexical file handles if you're looking for something to do :)

Re: globbing filehandles in arrays
by Fletch (Bishop) on Jan 23, 2009 at 13:42 UTC

    Well for starters you're trying to read from filehandles you've opened for writing. (And you're using C-style for loops, but that's more of a style issue :).

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

      Well for starters you're trying to read from filehandles you've opened for writing.
      Yes, this is true.. sorry about that (I've edited it now), it used to seem obvious to me which was which, but recently I've been getting them all backwards with the result that I've managed to write over files that I meant to read. Clever. At least I know I'm prone to do this kind of think and back up files before using them in a perl script!!

      (And you're using C-style for loops, but that's more of a style issue :).

      In mitigation, defence or whatever, I've been writing a lot of C lately. But out of interest, what is the stylistic 'problem' with that style of for loop? I kind of prefer it but am open to (logical :P) reasons why there are better ways.

      Cheers
      why_bird
      ........
      Those are my principles. If you don't like them I have others.
      -- Groucho Marx
      .......

        The PBP rationale is (very loosely (and probably poorly :) paraphrasing; see p100-101) that the Perl-style iteration is more explicit in that you can see right off what's being iterated.

        ## Compare . . . for( my $i = 0; $i < $#array; $i++ ) { frobnitz( $array[ $i ] ); } ## VS for my $item ( @array ) { frobnitz( $item ); }

        The first case the fact that it's working with each element of @array isn't as readily apparent (you've got to parse that it's looking at $#array and then match that up with the indexing); whereas the foreach-style comes right out up top and says "I'm frobnitz'ing every item of @array".

        Another thing is that in order to use the C-style loops you need to have an actual array to work with, whereas a foreach-style loop will work with any arbitrary list of values (e.g. for my $key ( sort { $h{$b} <=> $h{$a} } keys %h ) { ... }).

        Again it's just a style issue and it's not "wrong", per se; it just doesn't read as . . . "Perlish".

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

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (2)
As of 2024-04-16 23:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found