Bug in Perl script

I have a script that runs the ptail command with an open descriptor. After 30 seconds, I close the descriptor. But the descriptor is not closed. When the script is closed the tail is present in ps aux.

Code:
$log_file = path_to_log;
eval {
   local $SIG{ALRM} = sub { die; };
   alarm (30);
   open (LOG, "tail -F $log_file|") || die "Сan`t open logfile \"$log_file\"";
   while (<LOG>) {
       ***
   }
   alarm (0);
};
close (LOG);
print ("Ok\n");
exit(0);

This code is working well in FreeBSD 8.2, but in FreeBSD 9.0 it's not working.

--
Best Regards
Alexander
 
I think there is no such glob LOG outside eval block so your close ignored.
Anyway better if you dont use external programs in your script, so SirDice's suggestion is better
 
Alt said:
I think there is no such glob LOG outside eval block so your close ignored.

Good catch.

@vsityz: You really need to have this pragma if you're going to be writing Perl:
Code:
use warnings ]
 
anomie said:
@vsityz: You really need to have this pragma if you're going to be writing Perl:
Code:
use warnings ;
You'll want to use
Code:
use strict;
too.
 
I definitely would say to include strict in every script!
Moreover, it would be interesting to test your script against perlcritic, which could have provided a good guess:

Code:
Return value of "close" ignored at line 11, column 1.  Check the return value of "close" for success.  Severity: 2
 
I have rewritten this code:
Code:
eval {
      local $SIG{ALRM} = sub { die };
      alarm ($rtime);
      open (LOG, "$log_file") || die "error open logfile \"$log_file\"";
      seek (LOG, 0, 2);
      for (;;) {
         for ($curpos = tell(LOG); <LOG>; $curpos = tell(LOG)) {
              . . .
         }
         sleep (1);
         seek (LOG, $curpos, 0);
      }
      alarm (0);
      close (LOG);
};
This works well.
 
vsityz said:
I have a script that runs the ptail command with an open descriptor. After 30 seconds, I close the descriptor. But the descriptor is not closed. When the script is closed the tail is present in ps aux.

Code:
$log_file = path_to_log;
eval {
   local $SIG{ALRM} = sub { die; };
   alarm (30);
   open (LOG, "tail -F $log_file|") || die "Сan`t open logfile \"$log_file\"";
   while (<LOG>) {
       ***
   }
   alarm (0);
};
close (LOG);
print ("Ok\n");
exit(0);

This code is working well in FreeBSD 8.2, but in FreeBSD 9.0 it's not working.

--
Best Regards
Alexander

More on style:

The proper way to catch errors inside of an eval is to do something like:

Code:
my $eval_ok = do { local $@; eval { ... || die; } };
if (!$eval_ok) {
  # handle failure
} 
#else { .. }

You should also give Try::Tiny a look.
 
estrabd said:
The proper way to catch errors inside of an eval is to do something like:
I'd say it should be like
Code:
my $eRes = eval {
   ...;
   return 1;
};
unless( $eRes ) {
   ...;
}
Or maybe more simple variant:
Code:
eval {
   ...;
   return 1;
} || do {
   ...;
}
This cus some errors can put "0" or "" into $@ variable. Already got this kind of problem with DBI exceptions
 
One minor nit; in:

Code:
eval {
   ...;
   return 1;
} || do {
   ...;
}

I've recently learned to appreciate the extra-low precedence 'or'.


Code:
eval {
   ...;
   return 1;
} or do {
   ...;
}
 
Back
Top