0

I'm trying to assemble a script that will first identify the newest log file created under a folder, then open it and look for specific data. Basically, I will be looking in this log file for a specific error and print the errors into the new log file.

I understand how to perform sort in order to have the most recent file, but having trouble in reading the latest file and copying it to the new log file

use File::stat;

$dirname  = 'C:/Luntbuild_Logs';
$timediff = 0;

opendir DIR, "$dirname";

while ( defined( $file = readdir(DIR) ) ) {
    if ( $file ne "." && $file ne ".." ) {
        $diff = time() - stat("$dirname/$file")->mtime;
        if ( $timediff == 0 ) {
            $timediff = $diff;
            $newest   = $file;
        }
        if ( $diff < $timediff ) {
            $timediff = $diff;
            $newest   = $file;
        }
    }
}

print $newest;

$file1 = "$dirname/$file";

open( FILE1, "<$newest" );
my (@fprint) = <FILE1>;
close FILE1;

open( FOUT, ">list1.txt" ) || die("Cannot Open File");

foreach $line (@fprint) {
    print "$line" if $line =~ /> @/;
    print "$line" if $line =~ /ORA-/;
    print FOUT $line;
}

close FOUT;
matthias krull
  • 4,389
  • 3
  • 34
  • 54
user1587062
  • 5
  • 1
  • 4
  • What goes wrong? Why do you not use `or die` for both the opens? – choroba Aug 22 '12 at 13:23
  • possible duplicate of [Perl - sort the log files from a directory, pick up the latest generated log file and print only specific data](http://stackoverflow.com/questions/12050020/perl-sort-the-log-files-from-a-directory-pick-up-the-latest-generated-log-fil) – Toto Aug 22 '12 at 14:19

2 Answers2

3

The primary problem is that you build the full file path in $file1 but then open $newest which contains only the file name.

You really should improve your code by

  • Always using use strict and use warnings at the start of your program, and declaring all variables with my at their point of definition

  • Use lexical file and directory handles and the three-parameter form of open. Always test the status of an open and put $! in the die string so that you know why it failed

  • Never put double-quotes around a variable unless you know what it does and that is what you want

Here is a refactoring of your code which follows these guidelines and also uses the built-in -M operator that returns the age of a file in days

use strict;
use warnings;

my $dirname = 'C:/Luntbuild_Logs';
my ($newest_age, $newest_file);

opendir my $dh, $dirname or die $!;

while ( readdir($dh) ) {
  my $file = "$dirname/$_";
  next unless -f $file;
  my $age = -M $file;
  unless (defined $newest_age and $newest_age <= $age) {
    $newest_age = $age;
    $newest_file = $file;
  }
}

print $newest_file, "\n";

open my $out,'>', 'list1.txt' or die "Cannot open file: $!";

open my $in, '<', $newest_file or die $!;
while (<$in>) {
  print if /> \@/ or /ORA-/;
  print { $out } $_;
}

close $out or die $!;
close $in or die $!;
Community
  • 1
  • 1
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • `$file1` actually does not contain the correct file name: It contains the last file name from the readdir. – TLP Aug 23 '12 at 10:20
2

It looks like your error might lie here:

open(FILE1,"<$newest");

You try to open the file with no path included (readdir only returns file name), which may or may not work, depending on what your current working directory is.

Since you do not check the return value of the open statement, you don't know if it failed or not. Most likely, you need to do something like:

open FILE1, "<", "$dirname/$newest" or die $!;

Always check the return value of all open, and opendir calls, because they can fail silently. And be sure to include:

use strict;
use warnings;

In your script, and correct the errors and warnings. It is your safest precaution against hard to detect bugs.

TLP
  • 66,756
  • 10
  • 92
  • 149
  • Another problem is that you use "0" as the special value for "`$timediff` has not been set yet". Imagine that your `readdir` returns three file names: one file modified an hour ago, one file modified this very moment and one file modified 10 minutes ago. In that case it will set `$timediff` to 0 again upon seeing the second file and therefore think that the third file is actually the newest -- even though it wasn't. Or imagine file timestamps that are in the future (yes, such stuff happens in general). – Moritz Bunkus Aug 22 '12 at 13:51
  • 1
    Correct, it would be more prudent to leave `$timediff` undefined, and check for definedness. However, not the main problem with this code, I think. Unless there are a great many files, it would perhaps be a good idea to do `($newest, @others) = sort { -M $a <=> -M $b } readdir(DIR)` – TLP Aug 22 '12 at 14:00