rsync - create all missing parent directories?
RsyncScpRsync Problem Overview
I'm looking for an rsync
-like program which will create any missing parent directories on the remote side.
For example, if I have /top/a/b/c/d
on one server and only /top/a
exists on the remote server, I want to copy d
to the remote server and have the b
and c
directories created as well.
The command:
rsync /top/a/b/c/d remote:/top/a/b/c
won't work because /tmp/a/b
doesn't exist on the remote server. And if it did exist then the file d
would get copied to the path /top/a/b/c
.
This is possible to do with rsync
using --include
and --exclude
switches, but it is very involved, e.g.:
rsync -v -r a dest:dir \
--include 'a/b' \
--include 'a/b/c' \
--include 'a/b/c/d' \
--include 'a/b/c/d/e' \
--exclude 'a/*' \
--exclude 'a/b/*' \
--exclude 'a/b/c/*' \
--exclude 'a/b/c/d/*'
will only copy a/b/c/d/e
to dest:dir/a/b/c/d/e
even if the intermediate directories have files. (Note - the includes must precede the excludes.)
Are there any other options?
Rsync Solutions
Solution 1 - Rsync
You may be looking for
rsync -aR
for example:
rsync -a --relative /top/a/b/c/d remote:/
See also this trick in other question.
Solution 2 - Rsync
rsync -aq --rsync-path='mkdir -p /tmp/imaginary/ && rsync' file user@remote:/tmp/imaginary/
From http://www.schwertly.com/2013/07/forcing-rsync-to-create-a-remote-path-using-rsync-path/, but don't copy and paste from there, his syntax is butchered.
it lets you execute arbitrary command to setup the path for rsync executables.
Solution 3 - Rsync
i suggest that you enforce the existence manually:
ssh user@remote mkdir -p /top/a/b/c
rsync /top/a/b/c/d remote:/top/a/b/c
this creates the target folder if it does not exists already.
Solution 4 - Rsync
According to https://unix.stackexchange.com/a/496181/5783, since rsync 2.6.7, --relative
works if you use .
to anchor the starting parent directory to create at the destination:
derek@DESKTOP-2F2F59O:~/projects/rsync$ mkdir --parents top1/a/b/c/d
derek@DESKTOP-2F2F59O:~/projects/rsync$ mkdir --parents top2/a
derek@DESKTOP-2F2F59O:~/projects/rsync$ rsync --recursive --relative --verbose top1/a/./b/c/d top2/a/
sending incremental file list
b/
b/c/
b/c/d/
sent 99 bytes received 28 bytes 254.00 bytes/sec
total size is 0 speedup is 0.00
Solution 5 - Rsync
--relative
does not work for me since I had different setup.
Maybe I just didn't understood how --relative
works, but I found that the
ssh remote mkdir -p /top/a/b/c
rsync /top/a/b/c/d remote:/top/a/b/c
is easy to understand and does the job.
Solution 6 - Rsync
I was looking for a better solution, but mine seems to be better suited when you have too many sub-directories to create them manually.
Simply use cp
as an intermediate step with the --parents
option
cp --parents /your/path/sub/dir/ /tmp/localcopy
rsync [options] /tmp/localcopy/* remote:/destination/path/
cp --parents
will create the structure for you.
You can call it from any subfolder if you want only one subset of the parent folders to be copied.
Solution 7 - Rsync
A shorter way in Linux to create rsync destination paths is to use the '$_' Special Variable. (I think, but cannot confirm, that it is also the same in OSX).
'$_' holds the value of the last argument of the previous command executed. So the question could be answered with:
ssh remote mkdir -p /top/a/b/c/ && rsync -avz /top/a/b/c/d remote:$_
Solution 8 - Rsync
As of version 3.2.3 (6 Aug 2020), rynsc
has a flag for this purpose.
From the rsync
manual page (man rsync
):
--mkpath create the destination's path component