Setting ownership when copying or syncing files

In zsh, you could always do (as root) something like:

(cd tmp/ftp && tar cf - new-assests/) \
   > >(USERNAME=user1; cd ~user1/tmp && tar xopf -) \
   > >(USERNAME=user2; cd ~user2/html-stuff && tar xopf -)

That makes use of two zsh-specific features:

  • setting $USERNAME changes the shell process EUID, UID, GID, EGID and supplementary gids to that of the user as per the user database (as if the user had logged in with that username). Note that if the user doesn't exist in the database, that will be silently ignored by USERNAME=username, but cd ~username would then fail and cause the subshell to exit.
  • Redirecting a fd several times for output (here stdout, to two different process substitutions) triggers a tee like behaviour to send the output to the two targets (enabled with the mult_ios option, on by default). That saves reading the source twice.

Note that if any of the unpacking tar processes dies, that will likely interrupt the whole pipeline.

ksh or bash don't have that change-user features, but you could use su or sudo instead if available, and tee in place of the multios feature:

(cd tmp/ftp && tar cf - new-assests/) |
  tee >(cd ~user1/tmp && sudo -u user1 tar xopf -) |
  (cd ~user2/html-stuff && sudo -u user2 tar xopf -)

That assumes the target user has write permission to the target directory.

Some tar implementations have a --owner/--group or -chown/-chgrp options to override the user and group names of files stored in an archive. So another option would be to do something like:

(cd tmp/foo && tar --owner=user1 --group="$(id -g user1)" -cf - new-assets) |
  (cd ~user1/tmp && tar xpf -)

And repeat for user2.

In any of those, you may want to consider what to do if the files have ACLs as there's no one size fits all solution there.


Using rsync:

rsync -ai --chown=user1 tmp/ftp/new-assests/ ~user1/tmp/

This would copy the directory to the given location and at the same time change the ownership of the files to user1, if permitted.

The general form of the argument to --chown is USER:GROUP, but you may also use just USER to set a particular user as owner, as above, or just :GROUP to set a particular group (the : is not optional if you leave the user ID out).