4

I have a Perl script that works on Windows XP. It uses File::Copy's move function to move a directory tree to another place on the same drive. The script fails (silently) on Windows 2008. Nothing moved, nothing deleted.

I am using ActiveState Perl 5.10.0 Build 1005 and the File::Copy that comes with it.

Anyone know of issues with ActiveState Perl on Windows 2008 that might cause this?

Example script:

use File::Copy;
print "Move AAA to ZZZ\n";

move("AAA", "ZZZ");

print "Done.\n";
Garen
  • 941
  • 2
  • 9
  • 20
Paul Chernoch
  • 5,275
  • 3
  • 52
  • 73
  • 2
    Are you using strict and warnings? Are you running the script with appropriate permissions for the user running it, including the source and target directories? – Mark Canlas Jul 22 '09 at 20:12
  • @Mark: I'm surprised you didn't put that as an answer. – Powerlord Jul 22 '09 at 20:17
  • Concrete file paths might hint on permission related problems. – EFraim Jul 22 '09 at 20:30
  • I added use strict and warnings as suggested. No additional information reported. I switched from using relative paths to absolute ones - the problem remains. – Paul Chernoch Jul 22 '09 at 20:55
  • down-modded due to cross-posting between your perlmonks node - http://perlmonks.org/?node_id=782429 - and stack overflow. They asked to see code there. You posted it here – dwarring Jul 22 '09 at 22:53

6 Answers6

12

From the documentation:

RETURN

All functions return 1 on success, 0 on failure. $! will be set if an error was encountered.

The example fails silently because nothing is checking what $! is on failure. Try this:

move($from, $to) || die "Failed to move files: $!";
Community
  • 1
  • 1
caskey
  • 12,305
  • 2
  • 26
  • 27
  • I do as you said and I get the following: Move failed: No such file or directory at C:\Users\pchernoch\Documents\test.pl line 4. Of course the file IS there, which begs the next question: why can't it find the file? The directory is in my own Documents directory and was created by me, so permissions should not be a problem. – Paul Chernoch Jul 22 '09 at 20:53
  • 3
    The script may not be running in the same directory as the files. Either the source or destination must not exist. Don't forget that if you're moving to /a/b/c, /a/b must already exist. – caskey Jul 22 '09 at 20:54
  • Surprisingly, the directories were created read only. Quite a different set of defaults than XP. Took me by surprise. I changed them to read/write, but still doesn't work. – Paul Chernoch Jul 22 '09 at 20:58
  • caskey, you may be onto something. I will see what happens if I create the target dir first. But I was hoping for a file mover that would create the directory structure for me. – Paul Chernoch Jul 22 '09 at 21:00
  • I can see where you would think that. Perl just doesn't do things that way. There are more pieces you can pick up to make it happen: http://perldoc.perl.org/File/Path.html – caskey Jul 22 '09 at 21:06
8

If you don't want to have to check the return value, you can have autodie do it for you.

Since move() and copy() return a zero to indicate an error, and that's what autodie assumes, it's fairly straight forward.

use strict;
use warnings;
use File::Copy;

use autodie qw'copy move';

move("AAA", "ZZZ"); # no need to check for error, because of autodie

print "Done.\n";

Assuming that "AAA" doesn't exist, here is the output ( on STDERR ).

Can't move('AAA', 'ZZZ'): No such file or directory at test.pl line 7
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
  • Never heard of autodie. Nice feature. Thanks. – Paul Chernoch Jul 22 '09 at 21:03
  • I tried move on a single file and it works. Must be something having to do with directories. – Paul Chernoch Jul 22 '09 at 21:23
  • Try giving it the full path, or relative path to current directory. You may be giving it just the file names. If you're parsing a folder, and using that to give the file name, you won't be getting either the full path, or the relative path. – Brad Gilbert Jul 22 '09 at 22:29
2

I just encountered this myself, and in my particular situation, despite the exact same error ("No such file..."), it was actually that I had a file, from deep within the hierarchy I was renaming, open in a text editor somewhere. As soon as I closed that file, the error stopped occurring.

Kev
  • 15,899
  • 15
  • 79
  • 112
1

I've had weird things happen to me on Windows with moving and removing files. The solution was to use the CPAN module File::Remove.

singingfish
  • 3,136
  • 22
  • 25
  • 1
    I started looking for other Perl modules. File::Copy::Recursive looks promising. (It uses File::Copy to move individual files, but wraps it in a recursive script.) If I get it to work I will comment. The attraction of File::Copy is that it does a true file system move if it can, which is nearly instantaneous, whereas a Copy+Delete is slow. We are moving terabytes of data and it has to be fast. – Paul Chernoch Jul 23 '09 at 13:19
  • File::Copy::Recursive uses File::Copy::copy instead of move. Thus it does copy+delete instead of move. I will keep looking. – Paul Chernoch Jul 23 '09 at 13:51
1

Rather than slog through another half dozen Perl modules looking for one that did what I wanted, I adopted a hybrid approach and called out to DOS to use the "move" command. DOS move has its own peculiarities. For example, if you copy c:\temp\AAA to c:\temp\BBB and BBB exists already, you get c:\temp\BBB\AAA. But if BBB does not already exist, you get c:\temp\BBB, with no AAA underneath it. To avoid that, I first create BBB (if it does not exist) and then delete it. This causes all the directories down to BBB to be created if absent.

Here is my code:

sub move($$) {
    my ($source, $target) = @_;

    if (! -d $source) {
        print "    ERROR: Source directory does not exist: $source. Not copying to $target.\n";
    }
    elsif (-d $target) {
        print "    ERROR: Target directory already exists: $target. Not copying from $source.\n";
    }
    else {
        $source =~ s|/|\\|g;
        $target =~ s|/|\\|g;
        my $results = `if not exist "$target" mkdir "$target" & rmdir "$target" & move /Y "$source" "$target"`;
        print "    Results of move \"$source\" \"$target\":\n $results\n";
    }
}
Paul Chernoch
  • 5,275
  • 3
  • 52
  • 73
0

I too was finding move() and unlink() were failing on files that were created within the last 10 seconds. I added a call to 'sleep 10' before move() and it now works! Strange but true.

I then found http://answers.microsoft.com/en-us/windows/forum/windows_7-files/windows-7-does-not-refresh-folder-views/9d1ede23-2666-4951-b3b9-b6c1ce3d1ebf?page=23 which led me to adding...

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters

FileInfoCacheLifetime
FileNotFoundCacheLifetime
DirectoryCacheLifetime

as DWORD's set to 0... and now it works without the pause. Can't vouch for potential server performance impact though.

This seems like crazy default behaviour to me, and it's not restricted to Perl!

Also see Windows file share: why sometimes newly created files aren't visible for some period of time?

Community
  • 1
  • 1
MrBucket
  • 66
  • 3
  • Your answer applies to network shares. It doesn't seem relevant to this question. Also the question is over 4 years old. – Onots Feb 04 '14 at 01:23