Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

unlink fails to delete files with perculiar names

by DaveARoberts (Acolyte)
on Nov 22, 2011 at 08:03 UTC ( [id://939385]=perlquestion: print w/replies, xml ) Need Help??

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

I have a challenge with the perl unlink command. I use this in well established code to remove unwanted files - but recently I notice it fails with some files. I am using Windows 7, and Activstate binary build 1007 perl, v5.10.1 built for MSWin32-x86-multi-thread. Here's a code snippet...

my($no) = unlink $targ || carp "Unable to delete file $targ\n"; if ($no == 0){ printf " %s\n", $!; }else{ printf " %s\n", $no; }

So very simple... The variable $targ only ever has one file name. When the file to delete has unusual (illegal?) characters I observe the problem. For instance with a filename of

D:/Users/Dave/Documents/Personal/CV/~$rriculum Vitae - 09 June 2007.do +c
unlink reports the file deleted (and $no is set to 1 indicating one file deleted) - but in reality the file still exists. I suspect the error is generated by the tilde (~) and dollar character following directly after the directory seperator character (/), but can't figure out how to escape it.

I can stat the file before calling unlink (and it is found). Does anyone have a suggestion ? Thanks in advance

Replies are listed 'Best First'.
Re: unlink fails to delete files with perculiar names
by BrowserUk (Patriarch) on Nov 22, 2011 at 09:51 UTC

    If you had warnings enabled, you'd see that part of your filename is being taken as a perl variable for interpolation:

    $targ = "D:/Users/Dave/Documents/Personal/CV/~$rriculum Vitae - 09 Jun +e 2007.doc";; Use of uninitialized value $rriculum in concatenation (.) or string at + (eval 17) line 1, <STDIN> line 10.

    Just escape the $ with \:

    $targ = "D:/Users/Dave/Documents/Personal/CV/~\$rriculum Vitae - 09 Ju +ne 2007.doc";;

    And the subsequent unlink will likely work.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      The OP doesn't say how $targ was set.  It's merely speculation that he assigned it using a double-quoted literal. It might just as well have come from a readdir or whatever.

      Also, why would unlink have returned 1, as the OP states? That should only have happened in the (unlikely) case there also was a file 'D:/Users/Dave/Documents/Personal/CV/~ Vitae - 09 June 2007.doc' around at the time of the unlink call.

        It's merely speculation that he assigned it using a double-quoted literal

        Agreed. That's why likely work.

        It might just as well have come from a readdir

        But don't you have to combine the values from readdir with the path in order to get a fully qualified path?

        Could he be doing something like  $targ = "$path/$fname";?

        why would unlink have returned 1, as the OP states?

        Not sure, but that construct looks suspect to me: my($no) = unlink $targ || carp "Unable to delete file $targ\n";.

        What ends up in $no if unlink returns 0; the return value from carp()?


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        in my full code I get the file name using File::Find. From a windows directory listing from the command line the file is invisible, also from an explorer window...and from the application (MS word in this case) that presumeably created this as a temporary file it is also invisible.

      I tried escaping the $ with a \

      that did not work ....

        Then I suggest you try del "D:\Users\Dave\Documents\Personal\CV\~$rriculum Vitae - 09 June 2007.doc" on a command line and see what error message is produced by the shell.

        Update: Having seen one of your other replies, try doing:

        attrib -h -s -r "D:\Users\Dave\Documents\Personal\CV\~$rriculum Vitae +- 09 June 2007.doc"

        And then the unlink or del.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: unlink fails to delete files with perculiar names
by Eliya (Vicar) on Nov 22, 2011 at 08:58 UTC
    my($no) = unlink $targ || carp "Unable to delete file $targ\n";

    This doesn't explain your deletion problem, but you most likely meant

    my $no = unlink $targ or carp "Unable to delete file $targ\n";

    As you have it, the carp would only ever fire if $targ is false (e.g. ""), but not when the unlink failed.

Re: unlink fails to delete files with perculiar names
by moritz (Cardinal) on Nov 22, 2011 at 09:56 UTC

    Just a speculation: the variable name looks like it could be an automatic backup file from MS Word, and might be locked by the Word process, and thus not (easily) removable.

    Can you delete the file simply by pressing DEL in the Windows Explorer?

      I think you are right in that the file is an auto backup from word, and probably one that was orphaned some months back. Unfourtunatly the file cannot be seen in an explorer window, or from the dir command in a command window.

        Unfourtunatly the file cannot be seen in an explorer window, or from the dir command in a command window.

        hidden files require doing more than the default to see them

        Thinking more on this I think that you have touched on the source of the file (a temporary backup from an MS Office program - I have excel, word and powerpoint examples). If I try to delete a file using unlink with the application still open it complains (Permission denied).

        The code snippet is from a file replication utility. I think what has happened is that an oen file has been replicated, the original destroyed by the creating application, and then replaced by a subsequent replication event.

        The preventative cure is to prohibit the copy of a file with the pattern "/~$" in its path/name. The curative solution may be to delete any directory containing files with this pattern - and recreate what I want from a backup

Re: unlink fails to delete files with perculiar names
by Khen1950fx (Canon) on Nov 22, 2011 at 09:22 UTC
    Using File::Overwrite:
    #!perl use strict; use warnings; use File::Overwrite qw(overwrite_and_unlink); my $new_file = shift @ARGV; overwrite_and_unlink($new_file);
    Note: The file must be closed in order for this to work on Windows.
Re: unlink fails to delete files with perculiar names
by Anonymous Monk on Nov 22, 2011 at 09:20 UTC

    $ dir /b ~$
    File Not Found

    $ echo > "~$"

    $ dir /b ~$
    ~$

    $ perl -e " unlink '~$' or die $!"

    $ dir /b ~$
    File Not Found

    $ notepad > "~$"

    $ dir /b ~$
    ~$

    $ perl -e " unlink '~$' or die $!"
    Permission denied at -e line 1.

    $ perl -e " unlink '~$' or die qq/ $! \n $^E / "
    Permission denied
    The process cannot access the file because it is being used by another process at -e line 1.
Re: unlink fails to delete files with perculiar names
by ikegami (Patriarch) on Nov 22, 2011 at 18:06 UTC

    unlink reports the file deleted (and $no is set to 1 indicating one file deleted) - but in reality the file still exists.

    That means a program still has the file open. The file is marked to be deleted and will be deleted as soon no program has the file open anymore. Windows doesn't have anonymous files like unix does.

Re: unlink fails to delete files with perculiar names
by salva (Canon) on Nov 22, 2011 at 09:52 UTC
    Use some utility as Process Monitor to see what's going on at the OS level.
Re: unlink fails to delete files with perculiar names
by stefbv (Curate) on Nov 22, 2011 at 08:57 UTC

    Quote the argument of unlink.

    my($no) = unlink "$targ" || carp "Unable to delete file $targ\n";
      Putting the variable inside quotes is useless in this context.

        I think it is not useless it's about dealing with spaces in file names.

        Update: Sorry, made some further tests and I was wrong.

Re: unlink fails to delete files with perculiar names
by Marshall (Canon) on Nov 22, 2011 at 09:00 UTC
    unlink ($targ) || carp "Unable to delete file $targ\n";
    Unlink is different than "delete".

    Can you provide more information about how and why "unlink" does not work?

      Unlink is different than "delete".

      Do stop pushing this pointless distinction.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://939385]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (4)
As of 2024-04-19 20:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found