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.


  1. 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 (originally link and unlink)
    • Move across filesystems: recursive file copy followed by recursive unlink
  2. 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.