11

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; 
} 
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Mike
  • 1,841
  • 5
  • 24
  • 34

7 Answers7

8

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 :)

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • Thank you hobbs! The code works perfectly and now I can search multiple files for a specified string :) --------------- #!/usr/bin/perl { local @ARGV = ('F:\wyvern.txt', 'F:\casanova.txt'); while (<>) { print "$ARGV:$.:$_" if /Okay/; } continue { close ARGV if eof; } } ------------------------ But what should I do if I want to search all the files in a specified directory, say "novels" in the drive F? – Mike Oct 03 '09 at 05:27
  • 1
    Look at `glob()` to get files in one directory, and `File::Find::Object` or `File::Find::Rule` to find files in subdirectories. – hobbs Oct 03 '09 at 05:35
  • Thank you, hobbs! Things seem to be getting interesting for a beginner like me:) – Mike Oct 03 '09 at 05:45
4

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.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
  • How can I use the Windows perl-code and write the output into a text-File instead to the terminal? ... and thanks for this very useful code. – giordano May 09 '19 at 12:03
3

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

while (<>)
{
    print if m/Okay/;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
2

File::Grep is what you need here

ennuikiller
  • 46,381
  • 14
  • 112
  • 137
  • The documentation of File::Grep is too compact for those being new to it, do you maybe know a tutorial for beginners? – Wolf Nov 22 '17 at 13:46
2

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.

Mark
  • 1,304
  • 12
  • 22
1

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;
}
Lazy Bob
  • 449
  • 3
  • 9
  • @Lazy Bob, I changed ($line = ) to ($line = ) and retested the code again. It works great. Thanks for sharing the code. – Mike Oct 25 '09 at 03:35
0

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mike
  • 1,841
  • 5
  • 24
  • 34