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

I need to filter certain parts of an output file out to a summary. I have this which does the trick but sends prints to the screen. How can I output each match to a single file or array without overwriting the previous?
#!perl.exe my $filename="out.txt"; if (-r $filename) { open(FILE,$filename); while(<FILE>) { chomp; if (/^(.*)Datasource:/) { print "\n\n", $_, "\n"; } if (/^(.*)Passed:/) { $section="passed"; next; } elsif (/^(.*)Failed:/) { $section="failed"; print $_, "\n"; next; +} elsif (/^(.*)Exception:/) { $section="except"; print $_, "\n"; nex +t; } if ($section ne "passed") { if (/(^(.*)test\.)|(^(.*)Summary:)/) { print $_, "\n"; } } } close(FILE); } else { print("cant read file ",$filename,"\n"); }

Edit Masem 2001-10-22 - CODE tags
Edit kudra 2001-10-23 - changed title per ntc request

Replies are listed 'Best First'.
Re: simple regex question
by Fletch (Bishop) on Oct 22, 2001 at 20:50 UTC

    Just open an output file and print whatever you want to save off to that handle. perldoc perlopentut and perldoc -f open will explain more.

    Also, a style nit: using -r and friends on files you're about to open is redundant. Just open them and then deal with that failing.

    open( FILE, $filename ) or die "Can't open $filename for reading: $!\n"; ...

    Or something like this which is handy when you're looping over several files

    foreach my $filename ( @files ) { unless( open( FILE, $filename ) ) { warn "Couldn't open $filename: $!\n"; next; } ... close( FILE ); }

    Not using the test operators gets even more important when you get into writing files, since test-then-open isn't an atomic operation and you leave yourself open to race conditions.

Re: simple regex question
by suaveant (Parson) on Oct 22, 2001 at 21:52 UTC
    I would like to point out a couple regexp things...

    a) you are using capturing parenthesis without caring about what they capture... (i.e. you are not looking at $1 $2 etc...) in which case (?: ) is better to use, since it does not perform capturing.

    b) since you are not looking at what is in $1... the following /^(.*)Passed:/ is very inefficient. The following /Passed:/ is really all you need, and not capturing the .* will actually improve the efficiency. This will have the same effect, it will match a line with Passed: anywhere in it.

                    - Ant
                    - Some of my best work - (1 2 3)

Re: simple regex question
by mull (Monk) on Oct 22, 2001 at 21:11 UTC
    Hi,

    A useful thing for you to know would be that you can supply an optional filehandle argument to the print function if you would like to print to a file. This optional argument, when not present, defaults to STDOUT, which is why all your output has been printing to the screen. Try using something more like this:

    my $filename='out.txt'; my $output ='perl_output.txt'; if (-r $filename) { open(FILE, "< $filename"); open(OUTPUT, "> $output"); while(<FILE>) { chomp; if(/^(.*)Datasource:/){ print OUTPUT "\n\n", $_, "\n"; ... ... } close(FILE); close(OUTPUT); } else{ print("cant read file ",$filename,"\n"); }

    See, I opened a new file to hold the output, with a ">" to indicate that perl should create it if it isn't there already. The ">" also will make perl clobber that file each time you run the script, so if the output is important, you should save that somewhere else before you run it again.

    Later on in the loop, I print to the filehandle by using it as an argument to print. The final print statement has no extra argument, so it defaults to STDOUT and prints the error message to your screen.

    Of course, there is a lot more about standard functions like 'print' and 'open' in the perl documentation. On my system, I would use:

    perldoc -f print

    ... if I wanted to know more. Hope this was what you needed!

      Thanks mull, this is almost what i want but i also need to assign the whole match to an array at the same time.
        No problem, just push every line you want to save to an array:

        if (/Datasource:/) { print "\n\n", $_, "\n"; push @log, $_; }
        Modify all if-Blocks like this. BTW, since you append a '\n' to every line you print, there is no need to chomp it off first.

        pike

Re: simple regex question
by CubicSpline (Friar) on Oct 22, 2001 at 21:20 UTC
    BTW, the other guys didn't mention this, but if you want to open the file for "appending" (meaning adding on to the end of the file, which it sounds like is maybe what you want to do), then do it like this:
    open OUT, ">>filename.txt" or die("Can't open file for append!");