Search code examples
shellzshrsync

rsync : Copying all files into a destination directory with a different name


Given: A source directory /mnt1/src, a destination directory /mnt2/dest.

Problem: For a daily backup, I want to rsync all files in the tree under /mnt1/src into /mnt2/dest, so that for example /mnt1/src/foo/bar ends up into /mnt2/dest/foo/bar. Files below dest, which have no corresponding entry under src, should be deleted from dest.

Environment: zsh

I tried

rsync --delete -ra /mnt1/src/*(D) /mnt2/dest

This nearly works, but has the problem that for instance if I have an extraneous file dummy inside dest, which was for instance produced by

touch /mnt2/dest/dummy

, this file would not be removed, because the globbing (src/*(D)) does not contain this file and rsync therefore ignores it.

Of course I could do a

rsync --delete -ra /mnt1/src /mnt2/dest

and this would remove such extra files, but a file /mnt1/src/foo/bar would then end up in /mnt2/dest/src/foo/bar, which I don't want either.

I could do a

mv /mnt2/dest /mnt2/src
rsync --delete -ra /mnt1/src /mnt2
mv /mnt2/src /mnt2/dest

and this would do the job, but it looks unnecessarily complicated to me. Is there a way to accomplish my goal, without renaming directories before and after?


Solution

  • Per the comments, rsync is particular about whether there is a trailing '/' following the src operand. The presence or absence of the '/' controls whether the "contents-of" or the "directory-itself" is transferred, respectively. For example, in your case if you provide the trailing slash, e.g.

    rsync --delete -ra /mnt1/src/ /mnt2/dest
    

    Everything below /mnt1/src is transferred to /mnt2/dest.

    If you omit the '/' following src, the src directory itself (and everything below it) is transferred, resulting in /mnt2/dest/src/.... (not what you want)

    Additionally, you can tweak your options a bit. In -ra, the -r is duplicative as -a implies -rlptgoD. To insure you only copy new and updated files, add the -u option. The --delete option will delete files from dest not present in src.

    Putting it altogether, you could accomplish what you are attempting with:

    rsync -ua --delete /mnt1/src/ /mnt2/dest
    

    If you would like to see what is being transferred, add -v for verbose output, or I like the -i summary output. Good luck with your scripting. Let me know if you have questions.