#!/home/sburke/bin/perl use strict; unless(@ARGV > 1) { print STDERR <<'EOUSAGE' ; exit 1; Usage: findgrep regexp filespec patterns ...looks for lines matching the given regexp, in files named, or files matching patterns, e.g.: findgrep 'stuff\d*' '*.pl' EOUSAGE } #-------------------------------------------------------------------------- my $initial_RS = $/; sub taste_handle_RS ($;$) { # Taste the given input channel, set $/ as needed, and rewind back # over it again. # Sample use: # open(IN, $file); # my $nl = taste_handle_RS(*IN{IO}); # Optional second parameter is a byte count that the first line (plus newline) # is guaranteed to be smaller than. my $h = $_[0]; die "argument to taste_text_handle must be a IO-ref" unless ref $h and UNIVERSAL::isa($h, 'IO::Handle'); my $snip = ''; my $there = tell($h); read($h,$snip, $_[1] || 1024); # read seek($h,$there,0); # and rewind # to do: recognize unicode prefix? if(defined $snip and $snip =~ m<(\cm\cj|\cm|\cj)>s) { #print "$h\'s NL is ", unpack("H*", $1), "\n" if $Debug; #print "\$/ is ", unpack("H*",$/), "\n" if $Debug; $/ = $1; #print "\$/ is ", unpack("H*",$/), "\n" if $Debug; } else { #print "No newline in first 1K of $h?" if $Debug; $/ = $initial_RS; } return $/; } #-------------------------------------------------------------------------- my $matched = 0; my $files = 0; use File::Find; my $fregexp = shift @ARGV; sub simple_glob2re { # Doesn't keep '*' from matching .foo, tho. my $glob = $_[0]; '^' . join('', map { $_ eq '*' ? '.*' : $_ eq '?' ? '.' : quotemeta($_) } split '', $glob ) . '$'; } my $here; chomp($here = `pwd`); my @files; foreach my $item (@ARGV) { if($item !~ m) { # slashless next unless length $item; if(-e $item and -f _) { push @files, $item; } elsif(-d _) { find sub { push @files, $File::Find::name if -f $_ }, $item; chdir($here); } else { # it's a pattern for hereunder $item = simple_glob2re($item); find sub { push @files, $File::Find::name if m/$item/s and -f $_ }, './'; chdir($here); } } else { $item .= '/' if $item !~ m/[*?]/s and -d $item; # it's a dirname. Tweak so it matches the next pattern: my $path = $item; my $spec = ''; $spec = $1 if $path =~ s<([^/]+)$><>s; #print "<$path> <$spec>\n"; if(length $spec) { # no pattern find sub { push @files, $File::Find::name if -f $_ }, $path; chdir($here); } else { $spec = simple_glob2re($spec); find sub { push @files, $File::Find::name if m/$spec/s and -f $_ }, $path; chdir($here); } } } { my %seen; #@files = grep !(++$seen{$files}), @files; } die "No files match\n" unless @files; #print "Files: <@files> (", scalar(@files), ")\n"; my $short; foreach my $file (@files) { if($file =~ m<\.(gif|png|jpg|bmp|wav|au|exe|com|img|pdf|ps|mid|sit|mp3|hqx|uu|uue|swf|tgz|tar\.gz|zip|z|)$>is) { next; } elsif($file =~ m<\.gz>s) { $/ = "\n"; $short = $file; #$short = ($file =~ m<([^/]+)$>s) ? $1 : '????'; $file =~ s/([^a-z0-9A-Z.])/\\$1/g; # escape things open(IN, "gzip -c -d $file |") ||die "Can't open gzip -c -d $file| : $!\n"; } else { $/ = "\n"; $short = $file; #$short = ($file =~ m<([^/]+)$>s) ? $1 : '????'; #print "Norm-reading $file\n"; #$file =~ s/([^a-z0-9A-Z.])/\\$1/g; sysopen(IN, $file,0,0) or die "Can't sysopen-read $file: $!\n"; taste_handle_RS(*IN{IO}); } if($/ eq "\n") { while() { print "$short $.: $_" if m/$fregexp/io; } } else { while() { if(m/$fregexp/io) { chomp $_; print "$short $.: $_\n"; } } } close(IN); } exit; __END__