Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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
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
1  
While this works, I believe it does a copy/delete rather than a more efficient mv operation. – starfry Aug 28 '14 at 13:34

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

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

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .