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

O' Great Bearers of Perl Wisdom...

I want to use a variable in the FILEHANDLE in order to allow the number of pipes that I create to be flexible. The sample code that I have included is just an example of creating dynamic FILEHANDLEs. It doesn't work because perl doesn't recognize the FILEHANDLE with the added variable. This is eventually leading into how I use fork and return the results back to the parent process.
use strict; my %hash; my @dirs; @dirs = qw(ONE TWO THREE FOUR); for my $loop(@dirs) { pipe (FROM_CHILD_$loop, TO_PARENT_$loop) or die "Oops Pipe: $!\n"; select((select(TO_PARENT_$loop), $|++ )[0]); # set autoflush $|++; my $test = rand 5; # simulate processing print TO_PARENT_$loop "$test $loop\n"; } for my $loop(@dirs) { chomp( my $in = <FROM_CHILD_$loop> ); (my $value, my $key) = split(/\ /, $in); $hash{$key} = $value; } close FROM_CHILD_$loop; close TO_PARENT_$loop; for my $loop(keys %hash) { print "keys $loop => $hash{$loop}\n"; }

Replies are listed 'Best First'.
Re: FILEHANDLE with $var in name (for pipe)
by moodster (Hermit) on Apr 05, 2002 at 11:22 UTC
    I'm no expert on filehandles, but I believe it's possible to create a scalar reference to a filehandle (something like this):
    my $handle; open $handle, "filename";
    Then you can create an array of filehandle references and use your $loop variable to index that array. So, instead of FROM_CHILD_$loop, you'd use:
    $from_child[ $loop ]

    Cheers,
    --Moodster

      This requires perl-5.6 which is usually the version you download nowadays. More information can be found at recent perldelta.
Re: FILEHANDLE with $var in name (for pipe)
by mla (Beadle) on Apr 05, 2002 at 12:38 UTC
    Are you trying to do something like this?

    #!/usr/bin/perl use strict; use Symbol; my %hash; my @dirs; @dirs = qw(ONE TWO THREE FOUR); my %fh; for my $loop (@dirs) { my($from, $to) = (gensym, gensym); pipe ($from, $to) or die "Oops Pipe: $!\n"; select((select($to), $|++ )[0]); # set autoflush $|++; my $test = rand 5; # simulate processing print $to "$test $loop\n"; $fh{"FROM_CHILD_$loop"} = $from; $fh{"TO_PARENT_$loop"} = $to; } for my $loop (@dirs) { my $from = $fh{"FROM_CHILD_$loop"}; my $to = $fh{"TO_PARENT_$loop"}; chomp( my $in = <$from> ); (my $value, my $key) = split(/\ /, $in); $hash{$key} = $value; close $to; close $from; } for my $loop(keys %hash) { print "keys $loop => $hash{$loop}\n"; }

    The Symbol::gensym function returns a reference to an anonymous glob which can be used just like a normal file handle.

    And with recent Perls (sorry, I'm not sure how recent), you don't even need to call gensym; Perl handles it automatically, so you can just say:

    my($from, $to); pipe ($from, $to) or die "Oops Pipe: $!\n"; ... $fh{"FROM_CHILD_$loop"} = $from; $fh{"TO_PARENT_$loop"} = $to;
Re: FILEHANDLE with $var in name (for pipe)
by MadMax (Novice) on Apr 05, 2002 at 11:22 UTC
    UPDATE: I did finally manage to get this working (in a strange way), but I cannot get it to work with strict. I assigned the whole FILEHANDLE to a variable and used that variable as the FILEHANDLE. I could still use any suggestions on how to make it "better".
    # use strict; # I turned off strict because I get the following error with it on: # Can't use string ("FROM_CHILD_ONE") as a symbol ref while # "strict refs" in use at foo.pl line 16. Strict off seems to work?? my %hash; my @dirs; @dirs = qw(ONE TWO THREE FOUR); for my $loop(@dirs) { my $from = "FROM_CHILD_$loop"; my $to = "TO_PARENT_$loop"; pipe ($from, $to) or die "Oops Pipe: $!\n"; select((select($to), $|++ )[0]); # set autoflush $|++; my $test = rand 5; # simulate processing print $to "$test $loop\n"; } for my $loop(@dirs) { my $from = "FROM_CHILD_$loop"; my $to = "TO_PARENT_$loop"; chomp( my $in = <$from> ); (my $value, my $key) = split(/\ /, $in); $hash{$key} = $value; close $to; close $from; } for my $loop(keys %hash) { print "keys $loop => $hash{$loop}\n"; }
Re: FILEHANDLE with $var in name (for pipe)
by Zaxo (Archbishop) on Apr 05, 2002 at 13:10 UTC

    Your problem with strict comes from using symrefs for the handle names. Better to make the pipe with lexicals or, better yet, in a hash (untested):

    my $pipes = {}; for (qw/ ONE TWO THREE FOUR/) { pipe $pipes->{$_}{'FROM_CHILD'}, $pipes->{$_}{'TO_PARENT'}; #etc }
    It may be useful to use lexicals for their property of closing handles when they go out of scope:
    my $listen = {}; foreach $kid (qw/ ACE DEUCE TREY OOPS/ ) { $listen->{$kid} = do { my ($from,$to,$pid); pipe $from, $to; # fork and all, child closes $from, # deletes $listen, does child code and exits. { handle => $from, pid => $pid } }; }
    You might consider using a select loop instead of polling the kids.

    As kappa says, this is all dependent on having a recent perl.

    After Compline,
    Zaxo