Perl Script did not find the newest file

250 views Asked by At

I use the following perl script from "https://exchange.nagios.org/directory/Plugins/Operating-Systems/Linux/Check-Newest-files-age-and-size-in-Diredtory/" But in these script is an Error. The script is not showing the newest file. Can someone find the mistake? In the comments of the site have wrote somebody, that in line 22 the mistake is. I can't find it: Here is the code:

# Check that file exists (can be directory or link)
unless (-d $opt_f) {
        print "FILE_AGE CRITICAL: Folder not found - $opt_f\n";
        exit $ERRORS{'CRITICAL'};
}

my $list = opendir DIRHANDLE, $opt_f or die "Cant open directory: $!";

while ($_ = readdir(DIRHANDLE))
{
    $file=sprintf("%s/%s",$opt_f,$_);
    $attrs = stat("$file");
    $diff = time()-$attrs->mtime;
    if($temp == 0)
    {
        #$temp=$diff;
        $new=$file;
    }
    if($_ ne "." && $_ ne "..")
    {
        if($diff<$temp)
        {
            $temp=$diff;
            $new=$_;
        }
        else
        {
            $temp=$diff; $new=$_;
        }
    }
}

$st = File::stat::stat($opt_f."/".$new);
$age = time - $st->mtime;
$size = $st->size;

Example: I have some files on a filer (backups in a .img File). I use this script, to check the newest file size. If I create a new folder with a new file, the check looks to the correct file. But if I create a second file, the check looks to the old file anytime. If I create a third file, the check goes to the correct file. The fourth file is wrong and the fifth file is correct again(and so on)

3

There are 3 answers

3
Jeremy Jones On

An easy (easier?) way to do this would be to use the built-in glob function to read the directory instead of opening it, and then use simple file tests to sort the files by creation or modification time:

   my @files = sort {-M($a) <=> -M($b)} glob "*"; # or -C for creation
   # $files[0] is the newest file

A list of file test operators is at https://users.cs.cf.ac.uk/Dave.Marshall/PERL/node69.html

Note that -C and -M relate to when the script started, so for long-running or daemon scripts you might need to do something a bit different.

0
ikegami On

You want to find the earliest mtime, so we're talking about a simple comparison of the previously-found earlier mtime with the mtime of the current file. But there's so much code beyond that in what you posted ...and the first thing you do with the value you want to compare is change it? What?

Let's start over.

my $earliest_mtime = -1;
my $earliest_qfn;
while (defined( my $fn = readdir($dh) )) {
   next if $fn =~ /^\.\.?\z/;

   my $qfn = "$dir_qfn/$fn";
   my $stats = stat($qfn)
      or warn("Can't stat \"$qfn\": $!\n"), next;

   my $mtime = $stats->mtime;
   if ($mtime < $earliest_mtime) {
      $earliest_mtime = $mtime;
      $earliest_qfn = $qfn;
   }
}

if (defined($earliest_qfn)) {
   say $earliest_qfn;
}
1
Emmanuel S On

The biggest issue with the script seems to be that line 12 calls the core version of stat but line 13 expects the output to be that of File::stat::stat(). I suspect that testing for '.' or '..' should be done at the top of the while loop and all the variables should be defined before they are used.

As Jeremy has said, you're better off sorting an array of the files and pushing/poping the first/last value, depending on what you're looking for.