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

Ok, Monks, here is my situation.

I have a script which generates several hundred arrays (actually '.' delimited strings, but I figured turning them into arrays would make them easier to work with). I need to print each array to a separate file, depending upon the first entry in the array.

There are an indeterminate number of possible first entries, so I can't just use a big

if ( $first eq "somestr" ) { print FILE "$first\n"; }

elsif ( $first eq "someotherstr" ) { print SOMEOTHERFILE "$first\n"; }

type structure, although that captures the basic idea of what I want to do. It just won't work because I don't know have any pre-runtime values for what "somestr" and "someotherstr" could be.

Is there any way that I can pull out that first entry, and then use that variable to create a filehandle to print to?

Thanks in advance.

JAPH

Replies are listed 'Best First'.
Re: Variable Filehandles
by Fastolfe (Vicar) on Nov 02, 2000 at 22:27 UTC
    I'm not 100% sure what you're asking. It would help if we had some sample data and some example results.

    If you just have a string with items separated by dots, split might be able to do the job:

    use IO::File; ... my %fd; my %files = ( 'somestring' => 'somefilename', 'someother' => 'someother', ); my @items = ( 'somestring.this.content.will.go.into.somefilename', 'someother.this.will.go.into.someother', 'notthere.this.will.generate.a.warning', ); foreach @items { my @array = split(/\./); if (exists($files{$array[0]})) { $fd{$array[0]} ||= new IO::File "> $files{$array[0]}" or die "Couldn't open $files{$array[0]}: $!"; $fd{$array[0]}->print; } else { warn "No filename defined for $array[0]"; } } $fd{$_}->close for keys %fd;
    Or do you mean something more like this:
    my @array = ( [ 'somefilename', @data1 ], [ 'otherfilename', @data2 ], ); foreach @array { my $filename = shift(@{$_}); open(F, ">$filename") or die "Couldn't open $filename: $!"; print F join("\n", @{$_}), "\n"; }
    If that doesn't look like it helps you with your problem (or at least puts you on the track to adapting some of this to your solution), please give us more information.
(Ovid) Re: Variable Filehandles
by Ovid (Cardinal) on Nov 02, 2000 at 22:28 UTC
    Is there any way that I can pull out that first entry, and then use that variable to create a filehandle to print to?
    You're really going to have to give more information. How do you want to use the variable to create a filehandle? If you actually mean "use the variable to create a filename, you've begging for trouble. What happens if the variable is the same name as your script, or has ../../../ embedded in it? How would you prevent other files from being overwritten?

    Perhaps you should look into using Storable, FreezeThaw and Data::Dumper. This would allow you to take all of your data and just store it in a file, with names that you predetermine (this prevents filename conflicts).

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

Re: Variable Filehandles
by arturo (Vicar) on Nov 02, 2000 at 22:32 UTC

    Seems to me that FileHandle is a module that might help you out here. Roughly speaking, it lets you treat filehandles as regular scalars. That's very rough (see the module documentation for more info. It's a standard module)

    Philosophy can be made out of anything. Or less -- Jerry A. Fodor

      It is also an enormous speed hit, and you can already do that, either by using Symbol and then calling gensym, or with the following:
      my $fh = do {local *FH}; my $file = "foo.txt"; open ($fh, "> $file") or die "Cannot write '$file': $!"; print $fh "Hello world\n";
      And yes, you can keep filehandles in arrays, etc.

      But note that if you try to abuse this, you could run out of filehandles in your program. If lots of programs all open lots of filehandles, you could run out of filehandles on your machine. So it is best to not leave a million of these open...

      Its also out-dated. I beleive the standards now are the IO::blah modules (IO::File, IO::Handle, IO::Pipe, etc) which are also part of the standard, and that FileHandle.pm is only included to support old scripts. I've heard people complain about these as well, but if you try to use STDOUT as an object, perl demands IO::Handle
      prompt>perl -we "STDOUT->print('test')" Can't locate object method "print" via package "IO::Handle" at -e line + 1. prompt>perl -MIO::Handle -we "STDOUT->print('test')" test
      That's using 5.6 (ActiveState 613) on NT4, so I'm not sure how far back this goes. (And yes, that example also works under strict)
        Those are also slower.

        With Perl 5.6 you don't need to generate symbols. Just use a scalar as a filehandle and it Just Works.

Re: Variable Filehandles
by Anonymous Monk on Nov 02, 2000 at 23:38 UTC

    Data and example results:

    wfAtmInterfaceGroup.wfAtmCommonGroup

    wfAtmInterfaceGroup.wfAtmLinkModuleGroup

    wfAtmGroup.wfAtm

    wfAtmGroup.wfAtm.wfAtmDelete

    wfAtmInterfaceGroup.wfAtmCellSwitchGroup

    The result would be

    A file named "wfAtmInterfaceGroup.mib" would contain the text:

    wfAtmInterfaceGroup.wfAtmCommonGroup

    wfAtmInterfaceGroup.wfAtmLinkModuleGroup

    wfAtmInterfaceGroup.wfAtmCellSwitchGroup

    Another file named "wfAtmGroup.mib" would contain the text:

    wfAtmGroup.wfAtm

    wfAtmGroup.wfAtmDelete

    NOTES: This program is a total hack to get around some badly written MIBs files. I'm not worried about overwriting filenames, since I'll just dump the new files into an empty directory, and if they have the same base stem I *want* them going into the same file (obviously, all files will be opened for appending).

    Thanks for the help you have given so far, I'm going to go try out some of those solutions. No matter how many times I see it, I'm always amazed when a new post gets half a dozen answers in under an hour. Thanks for the help.

    The guy who asked the question

      It looks like the first code snippet in my first response does precisely what you're wanting.