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

Odd problem. I have a script that will move files to a new locations. Sample:
move("$base/$fname2", "$target/$user") || die "could not move $base/$fname2 to $target/$user: $!\n";
When I execute this I receive this error:
could not move /home/spacetest//nwatson/dir to /home/engineering/temp_space/nwatson: Invalid cross-device link
The new location is on a different filesystem (nfs mount).

Neil Watson
watson-wilson.ca

Edit by BazB: fixed signature tag.

Replies are listed 'Best First'.
Re: Moving files
by Somni (Friar) on Mar 22, 2004 at 18:15 UTC

    I'm assuming the move function you're using is from File::Copy. If it isn't than any of the following advice is invalid. Next time be sure to mention where you're getting a function if it's not a built-in operator.

    Despite what matija said, move() is indeed intended to be used for moving files across filesystem boundaries. It first attempts to rename, which in this case will fail, then it attempts to copy() and unlink.

    The problem appears to be that you're attempting to move a directory. Because the rename call fails move() is then calling copy(), which is intended for use on files, not directories.

    The solution, in Perl, is to move each individual file undir "$base/$fname2". First, chdir to your source directory, then use File::Find::find on "." to search. If you encounter a directory, create it in your target with mkdir; if you encounter a non-directory move it with File::Copy::move. Be sure to test it and play with File::Find::finddepth or File::Find's preprocess option if you're not getting things in the right order.

      That's awful. What was the design logic behind that? It would be faster to simply use system ("mv ...);

      Neil Watson
      watson-wilson.ca

        I think the author intended it to be used for files. He may be open to a suggestion to extend it for directories (or even a patch?).

        It would be faster to simply use system ("mv ...);

        Go ahead... Not as portable, but if you understand the constraints, there is nothing wrong with that at all.

        One other point to keep in mind is that using system() can be a security issue. Especially if you are passing user input to the system call.

        This node has a quick explanation of the issue.

Re: Moving files
by tinita (Parson) on Mar 22, 2004 at 18:01 UTC
    where's your move()-function coming from? my perl hasn't one.
    and if it's from File::Copy, then it should work across file systems:
    If possible, move() will simply rename the file. Oth- erwise, it copies the file to the new location and deletes the original.
Re: Moving files
by matija (Priest) on Mar 22, 2004 at 17:53 UTC
    This is not really a Perl problem. A lot of Unix systems simply don't allow the mv command to work between different devices (or even different partitions on the same device).

    The solution is to copy the file over, and then delete the original - or use GNU mv, which will do the same thing automaticaly.

Re: Moving files
by Roy Johnson (Monsignor) on Mar 22, 2004 at 18:12 UTC
    Any chance that double-slash in the source path is a problem?

    The PerlMonk tr/// Advocate
Re: Moving files
by zentara (Cardinal) on Mar 23, 2004 at 16:01 UTC
    Maybe File::NCopy and a File::Path will work?
    #!/usr/bin/perl use File::NCopy; use File::Path; $file = File::NCopy->new(recursive => 1); $file->copy($dir1, $dir2); # Copy $dir1 to $dir2 recursively rmtree([$dir1]);

    I'm not really a human, but I play one on earth. flash japh