I've got a script that's supposed to read files from a directory, and do pattern match on each file in the dir. If I run this script from within the dir that contains the files, it works fine but it fails to find any file if I run it from the parent dir.

#!/usr/bin/perl

use strict;

use warnings;

opendir my $DIR, '/home/tester1/logs/' or die "opendir .: $!\n";

print "$DIR\n";

my @files = grep /\.log$/i, readdir $DIR;

closedir $DIR;

# print "Got ", scalar @files, " files\n";

open my $out,'>',"report.txt";

foreach my $file (@files) {

open my $FILE, '<', $file or die "$file: $!\n";

while (<$FILE>) {

print $out $_ if /^<string to search>/;

}

close $FILE;

}

close $out;

This is the output I get ...

bash-4.1$ ./test.pl GLOB(0x200161f8) test1.log: A file or directory in the path name does not exist. bash-4.1$

Fishmonger explained what the problem is and how to solve it with readdir (i.e. prepending the file name with the path). But, instead of readdir, you might consider using the glob function, which returns the filenames with their relative or absolute path (depending on what you passed to glob).

So, I wanted to take this a little further and read multiple directories from the parent dir, and read multiple files from within each dir. In addition, I wanted to output a file for each of these directories based on a search pattern.

This is what I have so far but it doesn't seem to output anything except it prints the directory names...

Having said that, the code above was only a starting point for much more powerful constructs. You might also want to take a look at the File::Find module, which does something similar to this and many other useful things.

Besides the error pointed out by FishMonger (the use of $dir2 for refering to two different types of objects), I would suggest that you make the effort to format and especially to indent your code correctly and consistently, that will save you a lot of debugging time. Perhaps something like this (untested):

Please note that I made some other small editions to your code and added some comments here and there.

Now, after this reformating, the indentation show clearly where the flow control start and end instructions are and the program is much clearer to read and understand. You don't need to use the same indenting conventions I used above (such as 4 spaces for each indentation level), but you really need to be consistent.

Every good programmer that I know or have known is serious about code formating in general and indentation in particular. I would actually never hire a programmer writing source code with such sloppy formatting as the code in your post above.

Couldn't open: A file or directory in the path name does not exist. at ./Summary.pl line 22.

Line 22 is ...

open my $out,'>',"report_${dir2}.txt" or die "Couldn't open: $!";

Well, it depends what the $dir2 variable contains. If it is a path containing backslashes such as, e.g. "/usr/bin", they you end up trying to create a file named "report_/usr/bin.txt" and the OS is unlikely to let you open such a file (that is unless your current directory has a "report_" subdirectory having itself a "usr" sub-subdirectory, in which case it will happily create a "bin.txt" file in that sub-subdirectory provided you have sufficient privileges to to it).

Print to the screen the name of the file you are trying create right before your open command or in the message passed to the die function, the origin of the problem will probably be obvious.

This is a general rule of debuging (in most programming languages): when some command fails, add a print statement before it with all the parameters used and run again (or you might use the Perl debugger).

In addition, you might have to filter out the "." and ".." directories at the beginning of your program, you certainly don't want to cd to them nor to open files with these names.

Once I cd to "/home/tester1/logs/prod1", which is referenced by "$dir2", I want to create an output file in there named "report_prod1.txt". Then I cd to ""/home/tester1/logs/prod2", and create a file in there named "report_prod2.txt", etc.

Looks like you're getting a great handle on this! In case you're interested--and since installing the module's a bit too much, at this time--the following is functionally equivalent to the earlier post, sans File::Find::Rule:

It looks like your script creates output files for each input file that contains the search pattern, and then prepends each of the files with "report_" and appends it with ".txt"

Eg. It goes into each dir under "/home/tester1/logs" like prod1,prod2, etc. Then searches all files in prod1,prod2, etc for the string and creates output files for those. So, if prod1 contains files log1,log2,log3, but only log1 & logs2 has the string, it creates output files named report_log1.txt, report_log2.txt.

I was looking for something that creates only 1 file that contains the results from all the logs in prod1, and that file should be named "report_prod1.txt"

So, now the name of the output file is good but it looks like this file is being overwritten for every input file read. The list of files should probably be placed in an array, and then used in a for loop to parse through the array and print the output.