Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

So let's assume I have:

dest/dir/file1
dest/dir/file2
dest/dir/subdir/subfile1
dest/dir/subdir/subfile2

and

src/dir/file3
src/dir/subdir/subfile3
src/dir/newdir/anotherfile

... and let's assume there are thousands of files and subdirectories.

Now I want to move all the new files from src to dest, to their respective directories, creating new subdirectories when needed. This would be the equivalent of "cp -a src/dir dest/", but as a move operation. The obvious command "mv src/dir dest/" fails as the directory already exists in the destination.

How can I do this with one command?

share|improve this question
    
If there is a src/dir/file1, do you want to overwrite it on the dest copy? or preserve the older copy there? –  nik Sep 7 '09 at 13:07
    
@nik: In this scenario, there shoudn't be, so it doesn't matter. Preserving both dest/dir/file1 and src/dir/file1 would probably be the best option, since it mimics what mv would do. –  Ilari Kajaste Sep 8 '09 at 16:35
add comment

5 Answers 5

up vote 6 down vote accepted

You can use rsync.

rsync -av --remove-source-files src/ dest/

Unfortunately that won't remove the directories though. You could just add a further command to remove them.

share|improve this answer
    
Weird that there's no option to remove the directories. This is very close to the intent, anyway, so accepted. Is there a command to every empty directory in a directory tree (effectively removing the complete tree, if it is empty)? –  Ilari Kajaste Sep 8 '09 at 16:53
4  
I guess you could do find . -type d -empty -exec rmdir {} \; –  Dan Gravell Sep 9 '09 at 9:55
add comment

While the rsync option is better for simply moving files, here is another approach; using find to repeatedly invoke mv:

# First, move directories that don't exist on the destination:
(cd src/dir ; find * -type d -print) | while read f; do
   [ ! -d "src/dir/$f" ] || [ -d "dest/dir/$f" ] || mv "src/dir/$f" "dest/dir/$f"
done
# Then move individual files:
(cd src/dir ; find * -type f -print0) | xargs -0 -n1 -i@ /bin/mv src/dir/@ dest/dir/@

# Alternate to the xargs usage, to allow prompting before overwriting files:
(cd src/dir ; find * -type f) | while read f; do
    /bin/mv -i "src/dir/$f" "dest/dir/$f" </dev/tty
done

Note that:

  • _find * will skip any files/directories that start with a dot (".").
  • this will not remove the directories, either.

I use something along these lines, by nightly cron, to create any thumbnails of new images in my personal pictures archive, then use rsync to make a backup of all images on a 2nd machine.

share|improve this answer
add comment

It's not cp -a, the -a switch is the archive switch.

It should be cp -R, the recursive switch.

You can also add the -f switch to force overwrite.

share|improve this answer
    
Yes, but moving does preserve the file ownerships and timestamps, as -a does while -R doesn't. So -a is a better analogy for moving. –  Ilari Kajaste Sep 8 '09 at 16:30
add comment

As far as I know a recursive mv is not possible. I would suggest to perform a cp -R followed by a rm -r.

share|improve this answer
    
However when moving a directory tree from one volume to another, doesn't mv in fact perform a recursive move? –  Ilari Kajaste Sep 8 '09 at 16:41
1  
Unfortunately not. When mv operates on different volumes, it actually perform a cp followed by a rm. –  mouviciel Sep 8 '09 at 18:58
add comment

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.