Reputation: 27862
I have written a backup script that uses expect
to automate rsync
.
To make sure all files get backed up, I use rsync
's --rsync-path="sudo rsync"
option.
#!/bin/bash
set -e
expect <<- DONE
spawn rsync --rsync-path="sudo\\ rsync" -uav [email protected]:/home/myuser/ /backups/home/myuser
expect ":"
send -- "mypassword\r"
expect eof
DONE
This does not work as intended. I get the following error message:
bash: sudo rsync: command not found
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(226) [Receiver=3.1.1]
I have seen similar questions with respect to using spaces in a rsync
command line, and have added single quotes, double quotes, and escape backslashes here and there, but nothing has worked yet.
How do I make "--rsync-path
with spaces" work within an expect
script?
Upvotes: 0
Views: 849
Reputation: 137757
The problem is that you've got this:
--rsync-path="sudo\\ rsync"
Inside Expect/Tcl, this is seen as:
--rsync-path="sudo rsync"
And, because Tcl's quoting rules are not the same as bash's, that then uses "sudo rsync"
with the double quotes as the command to send to the remote side. Which confuses things terribly. The correct fix is to omit the double quotes; the (backslash-quoted) backslash will ensure that it all gets into spawn as one argument, and gets sent to the other side correctly.
I really don't like using HEREdocs with Tcl. Too many things can go weird when different sorts of quoting interact. It's much better to use a single script in the real target language, since then you can use variables to make things clearer:
#!/usr/bin/env expect
set remoteRsync "sudo rsync"
set from [email protected]:/home/myuser/
set to /backups/home/myuser
set pass "mypassword"
spawn rsync --rsync-path=$remoteRsync -uav $from $to
expect ":"
send -- "$pass\r"
expect eof
exit
This makes the structure of the code much simpler to see, and easier to debug. The bit with /usr/bin/env
at the start is just a way to avoid having the bash wrapper.
And no, those variables won't need quoting at use. Tcl is not bash.
Upvotes: 1
Reputation: 72737
You can't use --rsync-path
to do that, since what you want is word-splitting, i.e. something the shell does.
So how can you run a command that runs a command by specifying a single pathname?
On the remote system, write a script wrapper susync
doing the sudo
(don't forget to chmod 755
):
#!/bin/sh
exec /path/to/sudo /path/to/rsync "$@"
and use
spawn rsync --rsync-path=/path/to/susync ...
Upvotes: 1