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-files
1 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 regularmv
.
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 mergingmv
(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.