Merging folders with mv?

mv cannot merge or overwrite directories, it will fail with the message "mv: cannot move 'a' to 'b': Directory not empty", even when you're using the --force option.


You can work around this using other tools (like rsync, find, or even cp), but you need to carefully consider the implications:

  • rsync can merge the contents of one directory into another (ideally with the --remove-source-files1 option to safely delete only those source files that were transferred successfully, and with the usual permission/ownership/time preservation option -a if you wish)
    but this is a full copy operation, and can therefore be very disk-intensive.
  • Currently preferred option: You can combine rsync's --link-dest=DIR option (to create hardlinks instead of copying file contents, where possible) and --remove-source-files to get a semantic very similar to a regular mv.
    For this, --link-dest needs to be given an absolute path to the source directory (or a relative path from the destination to the source).
    but this is using --link-dest in an unintended way (which may or may not cause complications), requires knowing (or determining) the absolute path to the source (as an argument to --link-dest), and again leaves an empty directory structure to be cleaned up as per 1.
  • You can use find to sequentially recreate the source directory structure at the target, then individually move the actual files
    but this has to recurse through the source multiple times and can encounter race conditions (new directories being created at the source during the multi-step process)
  • cp can create hard links (simply put, additional pointers to the same existing file), which creates a result very similar to a merging mv (and is very IO-efficient since only pointers are created and no actual data has to be copied)
    but this again suffers from a possible race condition (new files at the source being deleted even though they weren't copied in the previous step)

Which of these workarounds (if any) is appropriate will very much depend on your specific use case.
As always, think before you execute any of these commands, and have backups.


1: Note that rsync --remove-source-files won't delete any directories, so you will have to do something like find -depth -type d -empty -delete afterwards to get rid of the empty source directory tree.


rsync -av /source/ /destination/
(after checking)
rm -rf /source/

You can use the -l option of the cp command, which creates hard links of files on the same filesystem instead of full-data copies. The following command copies the folder source/folder to a parent folder (destination) which already contains a directory with the name folder.

cp -rl source/folder destination
rm -r source/folder

You may also want to use the -P (--no-dereference - do not de-reference symbolic links) or -a (--archive - preserve all metadata, also includes -P option), depending on your needs.