#!/usr/bin/perl -w package File::Grep; use strict; use Carp; BEGIN { use Exporter (); use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = sprintf( "%d.%02d", q(0.01) =~ /\s(\d+)\.(\d+)/ ); @ISA = qw(Exporter); @EXPORT = qw(); @EXPORT_OK = qw( fgrep ); %EXPORT_TAGS = ( ); } sub fgrep (&@) { my ( $coderef, @files ) = @_; my $returntype; if ( wantarray ) { $returntype = 2; # Return everything } elsif ( defined( wantarray ) ) { $returntype = 1; # Return just the count } else { $returntype = 0; # Return at first match } my @matches; my $count; foreach my $file ( @files ) { if ( $returntype == 2 ) { push @matches, { filename => $file, count => 0, matches => [] }; } open FILE, "<$file" or carp "Cannot open file $file to grep: $!" and next; while ( my $line = ) { local $_ = $line; if ( &$coderef ) { $count++; last if ( $returntype == 0 ); # Last of while loop! if ( $returntype == 2 ) { $matches[-1]->{ count }++; push @{ $matches[-1]->{ matches } }, $line; } } } close FILE; if ( !$returntype && $count ) { return 1; } } if ( $returntype == 2 ) { return @matches; } elsif ( $returntype == 1 ) { return $count; } else { return 0; # Void context; if here, nothing was found, ever } } 1; __END__ =head1 NAME File::Grep - Find matches to a pattern in a series of files =head1 SYNOPSIS use File::Grep qw( fgrep ); # Void context if ( fgrep { /$user/ } "/etc/passwd" ) { do_something(); } # Scalar context print "The index page was hit ", fgrep { /index\.html/ } glob "/var/log/httpd/access.log.*", " times\n"; # Array context my @matches = fgrep { /index\.html } glob "/var/log/httpd/access.log.*"; foreach my $matchset ( @matches ) { print "There were ", $matchset->{ count }, " matches in ", $matchset->{ filename }, "\n"; } =head1 DESCRIPTION File::Grep mimics the functionality of the grep function in perl, but applying it to files instead of a list. This is similar in nature to the UNIX grep command, but more powerful as the pattern can be any legal perl function. While looking for patterns for files is trivally easy, File::Grep takes steps to be efficient in both computation and resources. Namely, if called in void context, it will short circuit execution when a match is located and immediately report truthfulness. In scalar context, it will only keep track of the number of matches and return that value. In array context, it will generate an array of hashes that include details on the matching -- specifically for each hash, key "filename" will be the name of the current file, "count" will be the number of hits, and "matches" will be an array reference containing the matched lines, in order of discovery. The ordering of this array will follow the same order of files as passed in from fgrep. The syntax for this command is similar to grep: fgrep BLOCK ARRAY. The block should be a subroutine that returns if a match was found or not. The variable $_ will be localized before this routine is called, so may be used to process the current line. Note, however, that only the original content of the line is saved in the array of hashes in array context. The array is a list of files to be grepped. If a file cannot be opened, a warning will be issued, though the function will continue to process remaining files; in addition, an entry in the array of hashes will still be created as to not mess up any indexing with the original file list. =head1 EXPORT "fgrep" may be exported, but this is not set by default. =head1 AUTHOR Michael K. Neylon, Emneylon-pm@masemware.comE =head1 SEE ALSO L. =cut