Tell me more ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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) ?

share|improve this question
this is a very good question. where i work ppl have solved the problem using some complex bash and awk scripts – biosFF Jun 11 '09 at 20:45
My preferred inefficient approach is cp -R tree1/* tree2 followed by deletion of tree1. – romkyns Aug 8 '11 at 13:02

8 Answers

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

share|improve this answer
1  
Are you sure this works ? For example; [thomas@ana ~]$ mkdir -p a/b [thomas@ana ~]$ touch a/b/c1 [thomas@ana ~]$ rsync -arv a a2 sending incremental file list created directory a2 a/ a/b/ a/b/c1 sent 125 bytes received 39 bytes 328.00 bytes/sec total size is 0 speedup is 0.00 [thomas@ana ~]$ touch a/b/c2 [thomas@ana ~]$ mv -u a/* a2 mv: cannot move a/b' to a2/b': Directory not empty [thomas@ana ~]$ mv -u -T a a2 mv: cannot move a' to a2': Directory not empty – Thomas Vander Stichele Jun 12 '09 at 9:42

the proposed mv -uf dir1/* dir2/ move the (sub)directories, not each file. you might try to use find

cd dir1
find . -type d -exec mkdir -p dir2/"{}" \;
find . -type f -exec mv -uf "{}" dir2/"{}" \;

or something similar

share|improve this answer

Does not

mv -uf tree1/* tree2/

work?

share|improve this answer
Nope: thomas@ana ~]$ mv -uf a/* a2/ mv: cannot move a/b' to a2/b': Directory not empty – Thomas Vander Stichele Jun 12 '09 at 9:47
mv: cannot move includes' to a subdirectory of itself, ../includes' - so it doesn't merge – romkyns Aug 8 '11 at 12:53

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.

share|improve this answer

You could use "cp -l & rm" for in-device moving:

cp -alv --backup=numbered tree1/* tree2 &&
rm -rf tree1/
  • -l of cp to use hard links instead of copying, (this also prevents cross-device operations)
  • --backup=numbered of cp for backing up the existing files in target directory

And be careful about this two issues:

  • use && to prevent your uncopied data to be removed, if you accidentally run it on cross-device targets. (in corss-device case cp exits with a status of "1", at least for GNU coreutils)
  • files starting with "." in tree1, you will lost them if there is any.
share|improve this answer

err

mv dir1/* dir2/

or simply

rsync -arv --remove-source-files  tree1/* tree2

should be enough, you will probably run into trouble at some point when too many entries are in dir1.

find sourcedir -maxdepth 1 -exec echo mv {} targetdir/ \;

should be a nice options

find sourcedir -maxdepth 1 -print0 |xargs -0 -I _ echo mv _ targetdir
find sourcedir -maxdepth1 -exec mv {} targetdir/ +

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.

share|improve this answer
This is not what I'm asking for. Your solution goes only one level deep and doesn't recurse into subdirectories. – Thomas Vander Stichele Jun 12 '09 at 9:48
It doesn't recurse because with the subsequent mv command it's not necessary to recurse any further than one directory. However since you started with rsync I recommend my the --remove-source-files switch which will keep you with the tool you know plus it won't use as much space as the rsync/rm combination. – Server Horror Jun 12 '09 at 10:02
On another note: since I just read your post again regarding the merging you might want to play with -n or -i options from mv – Server Horror Jun 12 '09 at 10:03
I'm pretty sure you're not considering the fact that most of the tree already exists in the destination, so your first mv command will not work. Not sure what -n or -i will help here. Please try the example. – Thomas Vander Stichele Jun 13 '09 at 7:41
cd /tree1
mv * /tree2

This won't move hidden files or folders, but your original example wouldn't either.

share|improve this answer

switch to directory you want to move and do

tar cf - * | ( cd /target; tar xfp -)

Quicker than mv...

share|improve this answer
1  
You meant quicker than cp right? – rkthkr Jun 11 '09 at 14:16
2  
Quicker the mv only if source and target are on different filesystems. – MikeyB Jun 11 '09 at 18:05
2  
This doesn't move inodes at all. – Thomas Vander Stichele Jun 12 '09 at 9:50

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.