user1518217
user1518217

Reputation: 614

rsync + ssh in python subprocess gets error with spaces in directory name

When I run my Python application (that synchronizes a remote directory locally) I have a problem if the directory that contains my app has one or more spaces in its name. Directory name appears in ssh options like "-o UserKnownHostsFile=<path>" and "-i <path>". I try to double quote paths in my function that generates the command string, but nothing. I also try to replace spaces like this: path.replace(' ', '\\ '), but it doesn't work. Note that my code works with dirnames without spaces. The error returned by ssh is "garbage at the end of line" (code 12) The command line generated seems ok..

rsync -rztv --delete --stats --progress --timeout=900 --size-only --dry-run \
    -e 'ssh -o BatchMode=yes \
    -o UserKnownHostsFile="/cygdrive/C/Users/my.user/my\ app/.ssh/known_hosts" \
    -i "/cygdrive/C/Users/my.user/my\ app/.ssh/id_rsa"'
    user@host:/home/user/folder/ "/cygdrive/C/Users/my.user/my\ app/folder/"

What am I doing wrong? Thank you!

Upvotes: 5

Views: 3533

Answers (3)

HorusKol
HorusKol

Reputation: 8706

Have you tried building your command as a list of arguments - I just had a similar problem passing a key file for the ssh connection:

command = [
  "rsync",
  "-rztv",
  "--delete",
  "--stats",
  "--progress",
  "--timeout=900",
  "--size-only",
  "--dry-run",
  "-e",
  "ssh -o BatchMode=yes -o UserKnownHostsFile='/cygdrive/C/Users/my.user/my\ app/.ssh/known_hosts' -i '/cygdrive/C/Users/my.user/my\ app/.ssh/id_rsa'",
  "user@host:/home/user/folder/",
  "/cygdrive/C/Users/my.user/my\ app/folder/"
]

sp = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = sp.communicate()[0]

Upvotes: 5

Joao Figueiredo
Joao Figueiredo

Reputation: 3188

To avoid escaping issues, use a raw string,

raw_string = r'''rsync -rztv --delete --stats --progress --timeout=900 --size-only --dry-run -e 'ssh -o BatchMode=yes -o UserKnownHostsFile="/cygdrive/C/Users/my.user/my app/.ssh/known_hosts" -i "/cygdrive/C/Users/my.user/my app/.ssh/id_rsa"' user@host:/home/user/folder/ "/cygdrive/C/Users/my.user/my app/folder/"'''

sp = subprocess.Popen(raw_string, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = sp.communicate()[0]

Upvotes: 0

newfurniturey
newfurniturey

Reputation: 38436

The returned data from the sub-command is including spaces as delimiters. Try updating the Internal Field Separator (IFS) list like:

# store a copy of the current IFS
SAVEIFS=$IFS;
# set IFS to be newline-only
IFS=$(echo -en "\n\b");

# execute your command(s)
rsync -rztv --delete --stats --progress --timeout=900 --size-only --dry-run -e 'ssh -o BatchMode=yes -o UserKnownHostsFile="/cygdrive/C/Users/my.user/my\ app/.ssh/known_hosts" -i "/cygdrive/C/Users/my.user/my\ app/.ssh/id_rsa"' user@host:/home/user/folder/ "/cygdrive/C/Users/my.user/my\ app/folder/"

# put the original IFS back
IFS=$SAVEIFS;

I haven't tested using your command, though it has worked in all cases I've tried in the past.

Upvotes: 0

Related Questions