# Bug in Perl script



## vsityz (Dec 9, 2011)

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*.


```
$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


----------



## SirDice (Dec 9, 2011)

My guess is that tail never quits because it doesn't receive an EOF.

This may be helpful: Perfaq5: How do I do a tail -f in perl?


----------



## Alt (Dec 9, 2011)

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


----------



## anomie (Dec 9, 2011)

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: 

```
use warnings ]
```


----------



## SirDice (Dec 12, 2011)

anomie said:
			
		

> @vsityz: You _really_ need to have this pragma if you're going to be writing Perl:
> 
> ```
> use warnings ;
> ```


You'll want to use

```
use strict;
```
too.


----------



## fluca1978 (Dec 12, 2011)

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:


```
Return value of "close" ignored at line 11, column 1.  Check the return value of "close" for success.  Severity: 2
```


----------



## vsityz (Dec 19, 2011)

I have rewritten this 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.


----------



## serverhamster (Dec 20, 2011)

Instead of _strict_ and _warnings_, you can also _use common::sense_. It can be found in devel/p5-common-sense.


----------



## estrabd (Jan 5, 2012)

You should also be using the 3-parameter open with a variable $FH, not a bare one (LOG).


----------



## estrabd (Jan 5, 2012)

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*.
> 
> 
> ```
> ...



More on style:

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


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

You should also give Try::Tiny a look.


----------



## Alt (Jan 6, 2012)

estrabd said:
			
		

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


I'd say it should be like 
	
	



```
my $eRes = eval {
   ...;
   return 1;
};
unless( $eRes ) {
   ...;
}
```
Or maybe more simple variant:
	
	



```
eval {
   ...;
   return 1;
} || do {
   ...;
}
```
This cus some errors can put "0" or "" into $@ variable. Already got this kind of problem with DBI exceptions


----------



## estrabd (Jan 6, 2012)

One minor nit; in:


```
eval {
   ...;
   return 1;
} || do {
   ...;
}
```

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



```
eval {
   ...;
   return 1;
} or do {
   ...;
}
```


----------

