1

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)

DavidO
  • 13,812
  • 3
  • 38
  • 66
steffen
  • 13
  • 3

3 Answers3

1

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.

Jeremy Jones
  • 4,561
  • 3
  • 16
  • 26
  • 1
    Re "*for long-running or daemon scripts you might need to do something a bit different.*", Nope. `( (stat($a))[9] - X ) / ( 24*60*60 ) <=> ( (stat($b))[9] - X ) / ( 24*60*60 )` works no matter what `X` is. – ikegami May 12 '21 at 17:31
  • 1
    If it's precision you're worried about, don't be. As long as your process runs for less than 285 million years, you're good :) – ikegami May 12 '21 at 17:37
  • Thanks, I think I meant that if the files/file times changed while the script was running the results might not be consistent, but I think that premise is incorrect too. Apologies. – Jeremy Jones May 12 '21 at 21:28
1

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;
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
0

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.

Emmanuel S
  • 21
  • 1
  • Re "*The biggest issue with the script seems to be that line 12 calls the core version of stat*", F::s replaces `stat` by default. It probably *doesn't* call the core`stat` as you claim – ikegami May 12 '21 at 22:29