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

I have two files: /tmp/carlist
DATSUN_BLUE TOYOTA_MAROON ELANTRA-YELLOW
/tmp/location
1250 1 engineer office DATSUN_BLUE office 67 page30 text 1500 1 billing office MERCEDES-TAN office 98 page 40 txt 1500 7 billing office JAGUAR-BLACK office 98 page 40 txt 1250 0 engineer office ELANTRA_YELLOW office 66 page50 txt 1250 1 engineer office DATSUN_BLUE office 67 page30 text
The second file has 100s of lines. I'd like to search for the patterns in the first file in the second file and save them into separate files. So the lines that have DATSUN_BLUE and the fields criteria would go to /tmp/Datsun.txt and the ones that contain TOYOTA_MAROON and criteria would go to /tmp/Toyota.txt, etc. I want the files to be created per line found in first file. So instead of one big file with the patterns, each time a pattern is found it would go to a separate file. I have tried, and I can create an $fh3 output file, but can't create separate files for each pattern in the first file. Does anyone have an idea?
open my $fh2, '<', '/tmp/location' or die "unable to open file for rea +ding : $!"; open my $fh1, '<', '/tmp/carlist' or die "unable to open file for rea +ding : $!"; chomp(my @carlist = <$fh1>); print "these are the policies @carlist\n"; close $fh1; my $pattern = join '', @carlist; my @strings; while (<$fh2>) { my @fields = split(',', $_); local $" = ','; if ( $fields[1] eq '1' || $fields[1] eq '0') { push @strings, $_ if /$pattern/; print $fh3 "@fields[0,4]\n" if /engineer/ && !/,-,/; } } close $fh2; close $fh1; close $fh3;

Replies are listed 'Best First'.
Re: how to save patterns found in array to separate files
by Athanasius (Archbishop) on Dec 28, 2015 at 06:18 UTC

    Hello 2015_newbie, and welcome to the Monastery!

    Since Perl v5.6, you can use lexical filehandles, which behave like other scalar variables. In this case, store the filehandles in a hash with each filehandle keyed to the corresponding filename base. The following code should give you the idea:

    #! perl use strict; use warnings; my @carslist = qw(DATSUN_BLUE TOYOTA_MAROON ELANTRA_YELLOW); my %cars; for (@carslist) { unless (exists $cars{$_}) { my $file = 'tmp/' . $_ . '.txt'; open(my $fh, '>', $file) or die "Cannot open file '$file' for writing: $!"; $cars{$_} = $fh; } } my $pattern = join '|', @carslist; $pattern = qr/$pattern/; my @strings; while (<DATA>) { chomp; my @fields = split; if (($fields[1] eq '1' || $fields[1] eq '0') && /$pattern/) { push @strings, $_; print { $cars{$fields[4]} } $fields[0], ',', $fields[4], "\n" if /engineer/ && !/,-,/; } } for (@carslist) { close $cars{$_} or die "Cannot close file '$_': $!"; } print "Strings:\n"; print "$_\n" for @strings; __DATA__ 1250 1 engineer office DATSUN_BLUE office 67 page30 text 1500 1 billing office MERCEDES_TAN office 98 page 40 txt 1500 7 billing office JAGUAR_BLACK office 98 page 40 txt 1250 0 engineer office ELANTRA_YELLOW office 66 page50 txt 1250 1 engineer office DATSUN_BLUE office 67 page30 text

    Output:

    16:14 >perl 1499_SoPW.pl Strings: 1250 1 engineer office DATSUN_BLUE office 67 page30 text 1250 0 engineer office ELANTRA_YELLOW office 66 page50 txt 1250 1 engineer office DATSUN_BLUE office 67 page30 text 16:14 >

    and the files DATSUN_BLUE.txt, TOYOTA_MAROON.txt, and ELANTRA_YELLOW.txt created and populated as required.

    Updates: (1) Note also that your script splits on commas, but the data you show is separated by whitespace. I’ve changed the split statement to just my @fields = split;, which is special-cased to split the default variable, $_, on whitespace (as though the pattern were /\s+/).

    (2) The braces are required around the filehandle expression in the line:

    print { $cars{$fields[4]} } $fields[0], ',', $fields[4], "\n" if /engi +neer/ && !/,-,/; # ^ ^

    because “whenever you’re using any expression more complex than a bareword handle or a plain, unsubscripted scalar variable ... you will have to use a block returning the filehandle value...” (perldoc print).

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Greetings Monk!! This works just incredibly fantastic! I was able to adopt the logic to other reports as well. This is my first experience with the monks -they're incredible. I have just one question, can you explain why the following works: $cars{$fields4} } $fields[0], ',', $fields4, "\n" The part I don't understand is why the need for {$cars{$fields[4]}} If I put other numbers than 4, I get compile errors. Why not just  $cars{$fields[0,4]} } This is probably a silly beginner question but I don't have much perl experience and am wondering why the "4" is necessary there.

        Hello again, 2015_newbie,

        A typical print statement has the following syntax:

        print FILEHANDLE LIST

        where LIST is a list of what things to print, and FILEHANDLE is a special value telling Perl where those things are to be printed. If FILEHANDLE is omitted, the destination defaults to the last selected filehandle — typically STDOUT, which means print to the screen. If you want your output to go to a file — as you do here — then you need to open the file for writing and associate that opened file with a filehandle variable; then you give that filehandle to print to tell it where to print to.

        Now, let’s return to the line:

        print { $cars{$fields[4]} } $fields[0], ',', $fields[4], "\n" if /engineer/ && !/,-,/;

        It might make things clearer if we add a couple of variables within the if clause:

        if (($fields[1] eq '1' || $fields[1] eq '0') && /$pattern/) { push @strings, $_; my $number = $fields[0]; my $model = $fields[4]; print { $cars{$model} } $number, ',', $model, "\n" if /engineer/ && !/,-,/; }

        Now it’s easier to see: in the LIST, the variable $model is what gets printed (second); but in the expression which denotes the filehandle, $model is the key corresponding to the filehandle stored in the hash %cars. So the value of $model (i.e., $fields[4]) might be DATSUN_BLUE (a string), but the corresponding hash entry, $cars{$model} (i.e., $cars{$fields[4]}), will be a special value — one which Perl understands — which identifies the file “tmp/DATSUN_BLUE.txt” as the file for print to write to.

        It might help you to study perldata to get a good grasp of arrays and hashes.

        Update: Corrected typo and improved wording.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,