First, if I understand your stated task, the common unix/gnu "grep" command already does what you want:
cd /path/to/search
grep -l pattern_to_find *
The two shell commands above do exactly what you were trying to do in perl (and if you're on a windows system, the gnu "bash" shell and "grep" are available for your OS -- since you have perl, you should know about these other tools).
There are a few problems with the OP script:
- You opendir() a path provided by the user and get file names, which is fine, but then you either need to chdir to that path, or else prepend the path string to each file name in order to open the file successfully. The OP script doesn't do either of those things
- You read the full content of every file into memory, but you don't need to do that, just read a line at a time until you either (a) reach EOF, or (b) find the first occurrence of the target pattern. In the latter case, you can print the file name, stop reading that file, and move on to the next. Big files will only increase the memory footprint if they happen to be binaries without any embedded line-breaks.
- You do a regex match on an array, but the =~ operator is supposed to be used on a single scalar value (one string) -- i.e. on each element of the array. That's another good reason just to read one line at a time, to check each line against the regex, and not use an array for file data.
- (added as an update:) You require the user to type input to the script after it starts running, rather than getting all the required user input from command-line args (using @ARGV) -- that gets really tiresome.
I'm not sure if you've given us the exact wording of the error message you got, and I'm not sure why you got a message like "readline() on closed filehandle" -- but that's the least of your problems. If you really don't want to use the existing "grep" command (e.g. if you want to use a regex that only Perl will support), then try something like this:
#!/usr/bin/perl
use strict;
use warnings;
my $Usage = "Usage: $0 [-p path/to/search] regex\n";
if ( @ARGV > 2 and $ARGV[0] eq '-p' ) {
shift;
chdir $ARGV[0] or die "Can't chdir to $ARGV[0]: $!\n";
shift;
}
die $Usage unless ( @ARGV == 1 );
my $regex = shift;
opendir( D, '.' );
my @files = grep { -f } readdir D; # we only want to look at data fil
+es
my @matches;
for my $f ( @files ) {
open( F, $f ) or do {
warn "open failed for $f: $!\n";
next;
};
while (<F>) {
if ( m{$regex} ) {
push @matches, $f;
last;
}
}
}
print "The pattern {$regex} was found in ", scalar @matches, " files:\
+n";
print "@matches\n";
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.