Alphaphi has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, I'd like to delete a complete path which sits on an NFS export, and the network is slightly unreliable.
33 use File::Path qw(make_path remove_tree); [...] 387 $result = eval { remove_tree "/path/to/tree"; }; [...]
Sometimes this fails due to network outages. In this case, the whole script dies:
cannot remove directory for /path/to/tree Directory not empty at /path/to/script line 387.
How can that be - remove_tree is trapped with eval¹? How can I make the script stay alive? What I want to do is to retry every second to remove the path until it's gone. However, this works:
387 $result = system( "rm -rf /path/to/tree" );
rm also complains from time to time that the directory is not empty, but at least the script stays alive, and I can retry. It then always succeeds on the second attempt. I never need a third one. But I obviously want to avoid the system call with it's fork.

So what is that makes remove_tree feel so unhappy?

Thanks.

¹ I have read http://perldoc.perl.org/File/Path.html which tells me that it might be a bad idea to trap remove_tree, but in my case I think it's OK.

Replies are listed 'Best First'.
Re: remove_tree dies even when trapped with eval
by afoken (Chancellor) on Jun 12, 2015 at 10:00 UTC
    system( "rm -rf /path/to/tree" );

    [...] But I obviously want to avoid the system call with it's fork.

    Good plan. But if, for some strange reason, it is unavoidable, please use the list form of system, i.e. system("/bin/rm","-rf","/path/to/tree") to avoid nasty surprises from the shell.

    I'd like to delete a complete path which sits on an NFS export, and the network is slightly unreliable. [...] rm also complains from time to time that the directory is not empty, but at least the script stays alive, and I can retry. It then always succeeds on the second attempt. I never need a third one.

    NFS caches some information about non-local files for a while (three seconds by default), without consulting the server. This may confuse the local system. See nfs(5).

    Depending on how the NFS export is mounted, access to it may block (hard mount) or fail (soft mount). Again, see nfs(5).

    Another funny thing that may happen is that another computer creates files in the directory tree that you are deleting. (Race Condition)

    And finally, consider making the network work more reliably.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: remove_tree dies even when trapped with eval
by choroba (Cardinal) on Jun 12, 2015 at 15:30 UTC
    Does the script really die because of that? I ran the following in one terminal:
    my $list = join ',', 'a' .. 'z'; mkdir '1'; open my $FH, '>', $_ for glob '1/' . ("{$list}" x 3);

    And while it was running, I ran the following in the same directory in the second terminal:

    use File::Path qw{ remove_tree }; print remove_tree('1'); print "FINISHED\n";

    I got the error message you mentioned, but "FINISHED" was printed, too, so the program didn't die. The documentation is somehow unclear on this:

    If make_path or remove_tree encounter an error, a diagnostic message will be printed to STDERR via carp (for non-fatal errors), or via croak (for fatal errors).
    If you just want to avoid the message, you can use the documented error option:
    use Data::Dumper; use File::Path qw{ remove_tree }; my $err; remove_tree('1', { error => \$err }); print Dumper($err);

    Which returns:

    $VAR1 = [ { '1' => 'cannot remove directory: Directory not empty' } ];
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: remove_tree dies even when trapped with eval
by Anonymous Monk on Jun 12, 2015 at 09:00 UTC
    What version of File::Path? Try the latest File-Path-2.09
      It is version 2.08, but it is not so easy to update, as potentially dozens of machines are affected, with no access to the internet. But as I read the release notes, it would be worth a try...
Re: remove_tree dies even when trapped with eval
by polettix (Vicar) on Jun 12, 2015 at 13:59 UTC
    Looking at the code, I see no reason why you cannot trap the error.

    Have you tried to see what's the error code that you get back from system when you use the workaround? Is the child process terminated due to some signal, and if yes by which one? See system for figuring out how to check this.

    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Io ho capito... ma tu che hai detto?