How to stop perl from exiting when stat($_)->size fails

P

Peter Juuls

In my script I fetch the filesize with stat($_)->size from File::stat.
Occasionally it fails although the file exists, and perl exits with this
error on STDERR: Can't call method "size" on an undefined value at
myscript.pl line 7.

I don't want the script to exit, instead I want to ignore the "bad" file and
continue with the next file. I have tried to do tests on file-existence
BEFORE the stat->size is executed, to prevent perl from exiting, but nothing
seems to work.

use File::stat
......
if ((-e $_) && (-r $_) && ($st = stat($_)) {
$bytes = stat($_)->size ;
}

How can I prevent the script from exiting? (ActiveStatePerl587 on
Windows2000)

Thanks
Best regards
Peter Juuls
 
X

xhoster

Peter Juuls said:
In my script I fetch the filesize with stat($_)->size from File::stat.
Occasionally it fails although the file exists, and perl exits with this
error on STDERR: Can't call method "size" on an undefined value at
myscript.pl line 7.

If you change it to:
(stat($_) or die $!)->size;
Then at least you will get the real error message.
I don't want the script to exit, instead I want to ignore the "bad" file
and continue with the next file. I have tried to do tests on
file-existence BEFORE the stat->size is executed,

You probably have a race condition, where the file exists the first 3 times
you stat it, but not the final time.
to prevent perl from
exiting, but nothing seems to work.

If you don't want Perl to exit, don't call the size method on an undefined
value. The easiest way to do that is to check the definedness of the value
before calling the method.
use File::stat
.....
if ((-e $_) && (-r $_) && ($st = stat($_)) {
$bytes = stat($_)->size ;
}


my $st=stat($_);
if (defined $st) {
$bytes=$st->size;
};


Xho
 
I

Ian Wilson

Peter said:
In my script I fetch the filesize with stat($_)->size from File::stat.
Occasionally it fails although the file exists, and perl exits with this
error on STDERR: Can't call method "size" on an undefined value at
myscript.pl line 7.

I don't want the script to exit, instead I want to ignore the "bad" file and
continue with the next file. I have tried to do tests on file-existence
BEFORE the stat->size is executed, to prevent perl from exiting, but nothing
seems to work.

use File::stat
.....

I hope "....." means "use Strict; use Warnings;"
if ((-e $_) && (-r $_) && ($st = stat($_)) {

perldoc File::Stat says
$st = stat($file) or die "No $file: $!";
It looks like you are discarding some useful info.

You could simplify this expression by using fewer parens with a lower
precedence operator and remembering that $_ is a default variable for
many operators. I'd write something like:
if ( -e and -r and ... ) {

Though I'm not certain that readability is a prerequisite for
determinimg the size of a file (is it?)

$bytes = stat($_)->size ;

Huh? See perldoc File::Stat for the correct usage!

You might end up with:
$bytes = $st->size if said:
}

How can I prevent the script from exiting? (ActiveStatePerl587 on
Windows2000)

In general, see
perldoc -f eval


I'd break the expression down into separate statements so that I could
report failures more fully:
"file '$_' does not exist!\n"
"unable to eval stat->size of '$_' because $@"
etc.

I'm unfamiliar with File::Stat and haven't tested the code quoted above,
so caveat emptor. Hopefully it will point you in the right direction.
 
P

Paul Lalli

Ian said:
I hope "....." means "use Strict; use Warnings;"

I don't, since both of those would give compiler errors in Unix, and
silently do nothing in Windows.
Huh? See perldoc File::Stat for the correct usage!

Well, (1) there's no such module, and (2) there's nothing at all wrong
with that usage. What do you think is wrong with it?
I'm unfamiliar with File::Stat and haven't tested the code quoted above,

Clearly. If you had, you wouldn't have chided the OP for perfectly
valid code. Perhaps you should reconsider that policy in the future.

Paul Lalli
 
P

Paul Lalli

Peter said:
In my script I fetch the filesize with stat($_)->size from File::stat.
Occasionally it fails although the file exists, and perl exits with this
error on STDERR: Can't call method "size" on an undefined value at
myscript.pl line 7.

I don't want the script to exit, instead I want to ignore the "bad" file and
continue with the next file. I have tried to do tests on file-existence
BEFORE the stat->size is executed, to prevent perl from exiting, but nothing
seems to work.

use File::stat
.....
if ((-e $_) && (-r $_) && ($st = stat($_)) {
$bytes = stat($_)->size ;
}

Why are you mixing the two distinct ways of using stat?

Try one of:

if (-e $_ and -r _ ) {
$bytes = -s _;
}

or:
use File::stat;
if ($st = stat($_) and $st->mode & 0400) {
$bytes = $st->size;
}
How can I prevent the script from exiting? (ActiveStatePerl587 on
Windows2000)

In this case, don't call a method on an undefined value - that is,
check the return value of stat() before you try to use that return
value as an object.

In the general case, if you have code that may fail, wrap it in an
eval{} block, and test $@ afterwords. This is Perl's means of
exception handling.
perldoc -f eval

Paul Lalli
 
P

Peter Juuls

Peter Juuls said:
I don't want the script to exit, instead I want to ignore the "bad" file
and
continue with the next file. I have tried to do tests on file-existence
BEFORE the stat->size is executed, to prevent perl from exiting, but
nothing
seems to work.

How can I prevent the script from exiting? (ActiveStatePerl587 on
Windows2000)

Thanks for your tips, everyone, I have replaced my old code with this code

use File::stat ;
......
my $st=stat($_);
if (defined $st) {
$bytes=$st->size;
};

This is an improvement, the script no longer exits when stat($_) fails for a
single file. It just skips the "bad" file, and that is what I want.
Still, I don't quite understand why it fails on a valid filename (I DO know
the file exists and is not accessed in other parts of my script or by other
programs), it happens seldomly, though, only once for several millions
files. A tip pointed out that this code gives me the real error message, so
I will use it to get to the bottom of the problem.

(stat($_) or die $!)->size;


Best regards
Peter Juuls
 
I

Ian Wilson

Paul said:
Well, <snip> there's nothing at all wrong
with that usage. What do you think is wrong with it?

I don't see a need to create $st and then throw it away.

From reading perldoc File::Stat I would use $st when invoking the size
method.

my $st = stat($_);
my $bytes = $st->size;

If you are going to invoke stat($_) twice (needlessly), once as part of
a conditional and again to obtain the size, then you should just be able
to do

if (-e and -r and stat($_)) {
my $bytes = stat($_)->size;
}

There's no need to save the results in $st if you never use it.

However the above still looks very 'wrong' to me, it invokes stat twice
needlessly, invokes -e and -r needlessly and discards all sorts of
information that I'd want to know about.

I'd do something like

#!/usr/bin/perl
use strict;
use warnings;
use File::stat;

$_ = 't.pl';

if (my $st = stat($_)) {
print "File $_ has size ", $st->size, " bytes\n";
} else {
die "Cannot stat($_) because $!";
}
 
I

Ian Wilson

Ian said:
I don't see a need to create $st and then throw it away.

From reading perldoc File::Stat I would use $st when invoking the size
method.

my $st = stat($_);
my $bytes = $st->size;

If you are going to invoke stat($_) twice (needlessly), once as part of
a conditional and again to obtain the size, then you should just be able
to do

if (-e and -r and stat($_)) {
my $bytes = stat($_)->size;
}

There's no need to save the results in $st if you never use it.

However the above still looks very 'wrong' to me, it invokes stat twice
needlessly, invokes -e and -r needlessly and discards all sorts of
information that I'd want to know about.

I'd do something like

#!/usr/bin/perl
use strict;
use warnings;
use File::stat;

$_ = 't.pl';

if (my $st = stat($_)) {
print "File $_ has size ", $st->size, " bytes\n";
} else {
die "Cannot stat($_) because $!";
}

I meant warn not die.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top