Sometimes I have two trees that used to have the same content, but have grown out of sync (because I moved disks around or whatever). A good example is a tree where I mirror upstream packages from Fedora.
I want to merge those two trees again by moving all of the files from tree1 into tree2.
Usually I do this with:
rsync -arv tree1/* tree2
Then delete tree1.
However, this takes an awful lot of time and disk space, and it would be much easier to be able to do:
mv -r tree1/* tree2
In other words, a recursive move. It would be faster because first of all it would not even copy, just move the inodes, and second I wouldn't need a delete at the end.
Does this exist ?
As a test case, consider the following sequence of commands:
$ mkdir -p a/b
$ touch a/b/c1
$ rsync -arv a/ a2
sending incremental file list
created directory
./
b/
b/c1
b/c2
sent 173 bytes received 57 bytes 460.00 bytes/sec
total size is 0 speedup is 0.00
$ touch a/b/c2
What command would now have the effect of moving a/b/c2 to a2/b/c2 and then deleting the a subtree (since everything in it is already in the destination tree) ?
Per the mv(1) manpage from gnu's
mv
:-u, --update move only when the SOURCE file is newer than the destination file or when the destination file is missing
the proposed
mv -uf dir1/* dir2/
move the (sub)directories, not each file. you might try to usefind
or something similar
Does not
work?
Midnight Commander (mc) is also nice for this kind of stuff. Tag files with CTRL-t, press F6, and when it asks to overwrite destination files, choose Update if you want to overwrite older files.
You could use "cp -l & rm" for in-device moving:
-l
ofcp
to use hard links instead of copying, (this also prevents cross-device operations)--backup=numbered
ofcp
for backing up the existing files in target directoryAnd be careful about this two issues:
&&
to prevent your uncopied data to be removed, if you accidentally run it on cross-device targets. (in corss-device casecp
exits with a status of "1
", at least for GNU coreutils).
" intree1
, you will lost them if there is any.Javier's answer with find works well, except that it doesn't remove the original directories. Add at the end:
err
or simply
should be enough, you will probably run into trouble at some point when too many entries are in
dir1
.should be a nice options
are both not really necessary because mv just takes 2 options (source target), so you will have to live with the multitude of processes in that case.
This won't move hidden files or folders, but your original example wouldn't either.
I think mv doesn't do what you think it does.
A unix filesystem has 3 components:
A directory entry points to an inode.
The inode has the metatadata about the file (is it a file, a directory, a named pipe? Who owns it? What are the permissions? What blocks does that inode use?
Blocks are the things that actually contain the contents of the file.
So -- when you "mv" a file, all you're really doing is unlinking the first directory entry and relinking it somewhere else.
No data ever gets duplicated / copied. You create the link snoopy, then you create the link woodstock, and then you delete the link snoopy. (things are a bit different with directories because typically you can't make hardlinked directories, but even so the "link" name just changes).
What if you're moving from one filesystem to another? In the old days, mv would just thrown an error and make it explicit that you can't move a file from one filesystem to another. These days, it seems like mv silently copies the data then deletes the original.
In the old days, because you couldn't move data from one file system to another, you got in the habit of using idioms like
tar -cf - . | (cd /new/location && tar -xf -)
then you delete the old data. Part of the reason for using tar was that in the old days, cp would destroy metadata like "this is a symbolic link" and "that's a hard link" and instead you'd just get new copies of that file as regular files. Even still, you need to give "cp" flags to tell it to preserve that sort of structure.
There is no way to avoid "moving" lots of data if it is from one filesystem to another. It doesn't matter if you're using fancy new move or rsync or tar or cpio.
But, if you keep all the data in the same filesystem, this:
mv /filesystem-1/big/directory* /filesystem-1/big2/
that will be extremely fast because it is just changing the directory entries and not actually moving any real data.
There are other issues at play, such as what should you do if there is already a file / directory in the new location as well as the source location?
None of the answers in this thread fit my usecase, so I came up with one on my own as a shell script.
At the heart of it is this function:
Which you could invoke like so (for the OP's usecase):
If source is a file or a directory for which the destination does not exist yet, it simply moves it with
mv -u
. If source is a directory for which the destination already exists, it iterates through its contents and recursively performs the same check followed by move|recurse with each of its members.I used
-u
because I only needed old files freshened and newer files untouched, but you could replace it with-f
for an unconditional move or-i
for an interactive one. Or not change anything and simplyrm -rf
your source after the script is done moving things.