Why can't mv deal with existence of same-name directory in destination?
mv
and rsync
are not similar programs. In particular, mv
is often attempting to simply rename objects. If it's in the same filesystem, it does not copy the contents at all.
If you didn't already have imperative_PLs/fortran
, then mv
would take the existing fortran
directory and rename it to that point in the tree.
But you already have a directory (with contents) at that location. Because a name can only reference a single object, the existing directory would have to be either removed or renamed. mv
assumes you don't want to do either and aborts.
rsync
instead copies the individual files and other contents inside fortran
and puts them into the existing imperative_PLs/fortran
directory.
Think of it as rename
instead, and the behavior might seem more understandable.
mv
is actually rename
under the cover.
If you move a file to another file, mv
assumes you know what you are doing and overwrite the destination file.
If you move a directory to another directory, mv
assumes you want to keep the basename of your original directory and create it on the target directory. If there is not yet a directory with that name on the destination side, or if a directory with that name exists but is empty, the operation succeeds.
However, if the target directory already exists and is not empty, this is no more a rename
but that should be a recursive file and directory removal. rename
isn't designed to do it so it fails, mv
doesn't go further as it assumes you didn't want to do it and fails too.
mv
doesn't work in this case because it's not been designed to do so. The system calls are (probably) either- Move to same filesystem:
rename
(originallylink
andunlink
) - Move across filesystems: recursive file copy followed by recursive
unlink
- Move to same filesystem:
Opinion: I think it's not so much that it was designed not to work, as it wasn't designed to handle this use case. For a "simple" tool that's intended to do one thing well you'd need to provide a set of switches to indicate to
mv
which of these action paths to take:- To bail with an error, as in the current implementation
- To merge, bailing with an error if a file already exists
- To merge, replacing any target files that already exist
If the merge/replace action is what you want, you can implement it easily enough with cp
followed by rm
, or by using one of the file tree copying utilities tar
, pax
, etc.