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

Hi - I have an if condition that if the file exists then only unlink the file,for some reason,even though the file is not present in the cwd,the code tries to unlink the file,any idea why?

ERROR:- Unable to unlink files.txt: No such file or directory at perl.pl line 2

my $file_name="files.txt"; my $filename="data.txt"; if ( (-e $file_name ) || (-e $filename)) {#enters the loop even though the files do not exist unlink $file_name or die "Unable to unlink $file_name: $!"; unlink $filename or die "Unable to unlink $filename: $!"; }

Replies are listed 'Best First'.
Re: Unlinking a file when the file doesnt exist
by moritz (Cardinal) on Mar 22, 2011 at 16:55 UTC
      A good reason for using this solution is that, in theory at least, you could have a possible race condition with your code. Between check for the existence of the file (-e) and deleting the file another process could have deleted it or even opened it.
        It's not a race condition. It doesn't matter when the file was created or haw many times it was created. The file should be gone and it's not.

      Unfortunately, $! is garbage in that example. It would only be meaningful if stat (via -e) failed. One definitely cannot count on it having any info about an unlink error.

      I recommend

      for my $file (qw(files.txt data.txt)) { unlink($file) or $!{ENOENT} or die("Unable to unlink '$file': $!"); }

      Or if one wants to clean up as many files as possible even if some can't be deleted,

      my $success = 1; for my $file (qw(files.txt data.txt)) { if (!unlink($file) && !$!{ENOENT}) { warn("Unable to unlink '$file': $!"); $success = 0; } } die("Unable to cleanup") if !$success;
        Unfortunately, $! is garbage in that example.

        It contained the right value when I tried it. Is that platform (or perl version) dependent?

        Unfortunately, $! is garbage in that example.

        From unlink:

        Deletes a list of files. On success, it returns the number of files it successfully deleted. On failure, it returns false and sets $! (errno):

        One of the examples at the perldoc page for unlink shows using $! with warn() in a foreach loop. Why shouldn't $! be used in this case?

      What if the file is actually a directory? I have never tried it but the documentation for unlink gives some warnings.

      How about:

      for my $file (qw(files.txt data.txt)) { unlink $file if -f $file; die "Unable to unlink '$file': $!" if -e $file; }

      Update: If the file tests are different then it would die after not attempting to delete a directory and $! would not be set. In that case -f is false and -e is true. If I make them the same that won't happen.

      for my $file (qw(files.txt data.txt)) { unlink $file if -f $file; die "Unable to unlink '$file': $!" if -f $file; }

      Better yet; do an unlink or warn.

      for my $file (qw(files.txt data.txt)) { if ( -f $file) { unlink $file or warn "Unable to unlink '$file': $!"; } }
Re: Unlinking a file when the file doesnt exist
by wind (Priest) on Mar 22, 2011 at 16:48 UTC
    Use separate if statements or change your existance check to &&.
    my $file_name = "files.txt"; if (-e $file_name) { unlink $file_name or die "Unable to unlink $file_name: $!"; } my $filename = "data.txt"; if (-e $filename) { unlink $filename or die "Unable to unlink $filename: $!"; }
Re: Unlinking a file when the file doesnt exist
by JavaFan (Canon) on Mar 22, 2011 at 18:06 UTC
    You enter the if statement if either file exists, and then you try to unlink both.