Infomaniak Network SA / Guy Baconniere
2007-Jun-06 10:45 UTC
add inverse recursive feature or do a mkdir -p/install -D -d ?
Hi,
Background :
I am using rsync to push/sync FTP uploaded files from master server
to slave servers. On slaves the full directory path of each file doesn't
exist so rsync is unable to sync it and there a no options in rsync to do
something like "mkdir -p/install -D -d" on destination before sync
file.
N.B. I don't want to do a full sync of the root/home directory every time
a file is uploaded somewhere in the hierarchy on the master server
Can you implement recursive make directory for the parents missing
on the destination ?
As alternative can you add an option to do a inverse recursive
syncronisation
of every parents directoy missing until full path is available on the
destination.
As workaround I have coded a little script rrsync.sh who do
an inverse recursive sync by calling rsync dry-run on every parents and
do a full rsync from the first parent available on destination.
TEST
$ mkdir -p test1/toto1/toto2/toto3/toto4
$ mkdir -p test2
$ touch test1/toto1/toto2/toto3/toto4/a
$ rsync -av test1/toto1/toto2/toto3/toto4 test2/toto1/toto2/toto3/toto4
building file list ... done
rsync: mkdir "/home/baco/test2/toto1/toto2/toto3/toto4" failed: No
such
file or directory (2)
rsync error: error in file IO (code 11) at main.c(529) [receiver=2.6.9]
rsync: connection unexpectedly closed (8 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(453)
[sender=2.6.9]
$ rsync -av test1/toto1/toto2/toto3/toto4/a test2/toto1/toto2/toto3/toto4/a
building file list ... done
rsync: push_dir#3 "/home/baco/test2/toto1/toto2/toto3/toto4" failed:
No
such file or directory (2)
rsync error: errors selecting input/output files, dirs (code 3) at
main.c(565) [receiver=2.6.9]
rsync: connection unexpectedly closed (8 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(453)
[sender=2.6.9]
$ ./rrsync.sh test1/toto1/toto2/toto3/toto4/a
test2/toto1/toto2/toto3/toto4/a
rsync -av test1/toto1 test2/toto1
$ ./rrsync.sh test1/toto1/toto2/toto3/toto4 test2/toto1/toto2/toto3/toto4
rsync -av test1/toto1 test2/toto1
$ rsync -av test1/toto1 test2/toto1
building file list ... done
created directory test2/toto1
toto1/
toto1/toto2/
toto1/toto2/toto3/
toto1/toto2/toto3/toto4/
toto1/toto2/toto3/toto4/a
sent 196 bytes received 66 bytes 524.00 bytes/sec
total size is 0 speedup is 0.00
$ ./rrsync.sh test1/toto1/toto2/toto3/toto4 test2/toto1/toto2/toto3/toto4
rsync -av test1/toto1/toto2 test2/toto1/toto2
$ ./rrsync.sh test1/toto1/toto2/toto3/toto4/a
test2/toto1/toto2/toto3/toto4/a
rsync -av test1/toto1/toto2 test2/toto1/toto2
CODE
#!/bin/bash
# rrsync.sh by Guy Baconniere
usage="$0 <src> <dst>"
src=${1:?$usage}
dst=${2:?$usage}
function crushedpath() {
path="${1:?give a path please}"
path=$(echo -n "${path}" | sed -e 's,/$,,')
pathdepth=$(echo -n "${path}" | sed -e 's,[^/],,g' |
wc -c)
echo "${path}"
for (( i=1; ${i} < ${pathdepth}; i=$(( ${i}+1 )) )); do
fpath=$(( ${pathdepth} - ${i} ))
subpath=$(echo -n "${path}" | cut -d "/"
-f1-${fpath})
if [ ! -z "${subpath}" ]; then
echo "${subpath}"
fi
done
}
function doublecrushedpath() {
src="${1:?give a src path please}"
dst="${2:?give a dst path please}"
src=$(echo -n "${src}" | sed -e 's,/$,,')
dst=$(echo -n "${dst}" | sed -e 's,/$,,')
srcdepth=$(echo -n "${src}" | sed -e 's,[^/],,g' | wc
-c)
dstdepth=$(echo -n "${dst}" | sed -e 's,[^/],,g' | wc
-c)
if [ $srcdepth -lt $dstdepth ]; then
maxdepth=$srcdepth;
else
maxdepth=$dstdepth;
fi
echo "${src} ${dst}"
for (( i=1; ${i} < ${maxdepth}; i=$(( ${i}+1 )) )); do
fsrc=$(( ${srcdepth} - ${i} ))
fdst=$(( ${dstdepth} - ${i} ))
subsrc=$(echo -n "${src}" | cut -d "/"
-f1-${fsrc})
subdst=$(echo -n "${dst}" | cut -d "/"
-f1-${fdst})
if [ ! -z "${subsrc}" ] || [ ! -z
"${subdst}" ]; then
echo "${subsrc} ${subdst}"
fi
done
}
function rrsync() {
src=${1:?src please}
dst=${2:?dst please}
doublecrushedpath "${src}" "${dst}" | while read
t_src t_dst; do
if ! rsync -nlD -- "${t_src}" "${t_dst}"
2>&1 \
| grep -q -E 'rsync: push_dir#3 "[^"]*"
failed: No such
file or directory'; then
echo rsync -av "${t_src}" "${t_dst}"
|| true
break
fi
done
}
#crushedpath "${dst}"
#doublecrushedpath "${src}" "${dst}"
rrsync "${src}" "${dst}"
--
Infomaniak Network SA
Guy Baconniere <baco@infomaniak.ch>
Unix System Administrator
Certified Linux Engineer (RHCE, LPIC-2)
Avenue de la Praille 26
1227 Carouge (Geneva)
Switzerland (CH)
Phone +41 (0)22 820 3541
Fax +41 (0)22 820 3546
AS29222 / BACO-RIPE
Wayne Davison
2007-Jun-06 15:55 UTC
add inverse recursive feature or do a mkdir -p/install -D -d ?
On Wed, Jun 06, 2007 at 12:31:39PM +0200, Infomaniak Network SA / Guy Baconniere wrote:> $ rsync -av test1/toto1/toto2/toto3/toto4 test2/toto1/toto2/toto3/toto4 > building file list ... done > rsync: mkdir "/home/baco/test2/toto1/toto2/toto3/toto4" failed: No such > file or directory (2)You can use --relative (-R) to send the path info as part of the sync: rsync -avR test1/./toto1/toto2/toto3/toto4 test2/ or cd test1 rsync -avR toto1/toto2/toto3/toto4 ../test2/ The "/./" idiom in the first example was added in rsync 2.6.7, and indicates the cut-off point between directories that are outside the transfer, and those that are included in the transfer. ..wayne..