Mike
Mike

Reputation: 1851

How can I search multiple files for a string in Perl?

My question is probably simple but I'm a complete newbie. I want to search the contents of multiple text files for a particular phrase and then display the lines of the finds on screen. I've already learnt how to deal with a single file. For example, if I want to search for a word, say "Okay" in a text file named "wyvern.txt" in the root directory of F. The following code works:

#!/usr/bin/perl

$file = 'F:\wyvern.txt';
open(txt, $file);
while($line = <txt>) {
  print "$line" if $line =~ /Okay/;
}
close(txt);

But what should I do if I want to search for the same phrase in two text files, say "wyvern' and "casanova" respectively? or how about all the files in the directory "novels" in the root directory of F.

Any help would be greatly appreciated. Thanks in advance

Mike

Edit:

Haha, I finally figured out how to search all the files in a directory for a pattern match:) The following code works great:

#!/usr/bin/perl  
@files = <F:/novels/*>;
foreach $file (@files) {
open   (FILE, "$file");
while($line= <FILE> ){
print "$line" if $line =~ /Okay/;
}
close FILE; 
} 

Upvotes: 11

Views: 33591

Answers (7)

Mark
Mark

Reputation: 1304

Just a tweak on your line: <F:/novels/*>, I prefer to use the glob keyword - it works the same in this context and avoids the chances of confusing the many different uses of angle brackets in perl. Ie:

@files = glob "F:/novels/*";

See perldoc glob for more.

Upvotes: 2

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118118

On a system where command line arguments are properly expanded, you can use:

[sinan@host:~/test]$ perl -ne 'print "$.:$_" if /config/' *
1:$(srcdir)/config/override.m4

The problem with Windows is:

C:\Temp> perl -ne "print if /perl/" *.txt
Can't open *.txt: Invalid argument.

On Windows, you could do:

C:\Temp> for %f in (*.txt) do perl -ne "print if /perl/" %f

But, you might just want to use cmd.exe builtin findstr or the grep command line tool.

Upvotes: 4

Mike
Mike

Reputation: 1851

Okay, I'm a complete dummie. But to sum up, I now can search one single text file or multiple text files for a specified string. I'm still trying to figuring out how to deal with all the files in one folder. the following codes work.

Code 1:

#!/usr/bin/perl
$file = 'F:\one.txt';
open(txt, $file);
while($line = <txt>) {
  print "$line" if $line =~ /Okay/;
}
close(txt);

Code 2:

#!/usr/bin/perl
{
  local @ARGV = ('F:\wyvern.txt', 'F:\casanova.txt');
  while (<>) {
    print "$ARGV:$.:$_" if /Okay/;
  } continue {
    close ARGV if eof;
  }
}

Thanks again for your help. I really appreciate it.

Upvotes: 0

hobbs
hobbs

Reputation: 239652

Extending the good answer provided by Jonathan Leffler:

The filename where the match was found is in $ARGV, and with a small change, the line number can be found in $.. Example:

while (<>) {
  print "$ARGV:$.:$_" if /pattern/;
} continue {
  close ARGV if eof; # Reset $. at the end of each file.
}

Furthermore, if you have a list of filenames and they're not on the commandline, you can still get the magic ARGV behavior. Watch:

{
  local @ARGV = ('one.txt', 'two.txt');
  while (<>) {
    print "$ARGV:$.:$_" if /Okay/;
  } continue {
    close ARGV if eof;
  }
}

Which is a generally useful pattern for doing line-by-line processing on a series of files, whatever it is -- even if I might recommend File::Grep or App::Ack for this specific problem :)

Upvotes: 8

ennuikiller
ennuikiller

Reputation: 46965

File::Grep is what you need here

Upvotes: 2

Lazy Bob
Lazy Bob

Reputation: 449

put the files in a for loop, or something along those lines:

i.e.

for $file ('F:\wyvern.txt','F:\casanova.txt') {

open(TXT, $file);
while($line = <txt>) {
     print "$line" if $line =~ /Okay/;
    }
close TXT;
}

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 753455

The easiest way is to list the files on the command line, and then simply use:

while (<>)
{
    print if m/Okay/;
}

Upvotes: 3

Related Questions