33

I need to "install" a bunch of files to another directory keeping the directory structure of the source files intact. For example, if I have ./foo/bar/baz.txt going to /var/www/localhost/webroot/ I want the result to be /var/www/localhost/webroot/foo/bar/baz.txt. rsync has this capability in --relative, but when I did this I discovered it wasn't friendly to symlinks:

$ ls -ald /var/www/localhost/webroot/ | grep ^l
lrwxrwxrwx  1 www-data www-data     15 2014-01-03 13:45 media -> ../static/media
lrwxrwxrwx  1 root     root         13 2014-02-24 13:47 var -> ../static/var
$ rsync -qrR . /var/www/localhost/webroot/
$ ls -ald /var/www/localhost/webroot/ | grep var
drwxr-xr-x 3 root root 4096 2014-02-24 13:52 /var/www/localhost/webroot/var

So you see the symlink is no longer a symlink – the files were copied to the wrong place!

rsync also has the --no-implied-dirs option, that superficially seems to do what I want, but it only works as I intend when not doing a recursive rsync, so I have to:

find . -type f -print0 | xargs -0I{} rsync -R --no-implied-dirs {} /var/www/localhost/webroot/

Is there any more direct way to accomplish this mirroring of files without wiping out intermediate symlink directories (with or without rsync)?

0

4 Answers 4

43

Use rsync's option -K (--keep-dirlinks). From the manpage:

 -K, --keep-dirlinks
      This  option  causes  the  receiving side  to  treat  a
      symlink  to  a  directory  as though  it  were  a  real
      directory, but only if it matches a real directory from
      the  sender.   Without   this  option,  the  receiver’s
      symlink  would  be deleted  and  replaced  with a  real
      directory.

      For example, suppose you  transfer a directory foo that
      contains a file file, but foo is a symlink to directory
      bar  on  the  receiver.  Without  --keep-dirlinks,  the
      receiver  deletes  symlink  foo,   recreates  it  as  a
      directory,  and   receives  the   file  into   the  new
      directory.   With --keep-dirlinks,  the receiver  keeps
      the symlink and file ends up in bar.

      One note  of caution:  if you  use --keep-dirlinks, you
      must  trust all  the symlinks  in the  copy!  If  it is
      possible  for an  untrusted  user to  create their  own
      symlink to  any directory,  the user  could then  (on a
      subsequent  copy)  replace  the  symlink  with  a  real
      directory and affect the  content of whatever directory
      the  symlink references.   For backup  copies, you  are
      better off using something like a bind mount instead of
      a symlink to modify your receiving hierarchy.

      See also  --copy-dirlinks for  an analogous  option for
      the sending side.
18

I wanted to preserve my symlinks as symlinks. For that you can use the -l option.

    -l, --links                 copy symlinks as symlinks

Since I was copying frameworks on OS X, I found this helpful.

6

Please use -a, as it implies -l as was supposed above. But it also contains other important options if you want a complete copy of the source.

Also: As I understand the man page, -K is meant for symlinks on the receiver side. I don't think this should be the correct answer here.

2

As a non-rsync answer, the tar utility can perform this task. Use two instances of tar on either side of a pipe, the first to consume a directory structure and the second to extract it elsewhere. File ownership of the copy will likely change, while the permission modes will likely remain unchanged.

Many examples exist and I found the suggestions in this answer relatively quickly: https://unix.stackexchange.com/a/59108/34251.

Edit
A second (more succinct?) example: https://unix.stackexchange.com/a/19824/34251.

You must log in to answer this question.

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