【问题标题】:rsync + ssh in python subprocess gets error with spaces in directory namepython子进程中的rsync + ssh在目录名称中出现空格错误
【发布时间】:2012-07-11 15:33:08
【问题描述】:

当我运行我的 Python 应用程序(在本地同步远程目录)时,如果包含我的应用程序的目录的名称中有一个或多个空格,我会遇到问题。 目录名称出现在 ssh 选项中,例如“-o UserKnownHostsFile=<path>”和“-i <path>”。 我尝试在生成命令字符串的函数中使用双引号路径,但没有。我也尝试像这样替换空格:path.replace(' ', '\\ '),但它不起作用。 请注意,我的代码适用于不带空格的目录名。 ssh 返回的错误是“行尾垃圾”(代码 12) 生成的命令行似乎没问题..

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/"

我做错了什么?谢谢!

【问题讨论】:

  • 在从 Python 调用它之前,这个命令在你的 shell 中真的有效吗?我不确定您是否是 a) 成功访问 known_hosts 文件 b) 成功地在两个主机之间预先建立了 ssh 隧道
  • 是的,当路径名中有空格时,它在 Python 中有效。

标签: python ssh rsync quoting


【解决方案1】:

您是否尝试过将命令构建为参数列表 - 我在为 ssh 连接传递密钥文件时遇到了类似问题:

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]

【讨论】:

  • 使用列表而不是压缩字符串为我解决了很多引用/转义问题,超出了这里提到的内容。谢谢
【解决方案2】:

子命令返回的数据包含空格作为分隔符。尝试更新内部字段分隔符 (IFS) 列表,例如:

# 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;

我没有使用你的命令进行测试,尽管它在我过去尝试过的所有情况下都有效。

【讨论】:

  • 对不起,我在 Python 中(准确地说是在子进程中调用命令)
【解决方案3】:

为避免转义问题,请使用原始字符串,

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]

【讨论】:

  • 我在你的 raw_string 中插入了我的变量,像这样:r'''-e 'ssh -o BatchMode=yes -o UserKnownHostsFile="''' + basePath + self.__knownHostsPathName + ''' " -i "''' + basePath + self.__certPathName + '''"' ''' + self.__srcUser + '@' + self.__srcHost + ':' + srcPath + ''' "''' + basePath + dstPath + '''"''' 但我总是得到“命令行第 0 行:行尾垃圾”。
  • 你为什么要这样做..?您正在破坏使用原始字符串工具的目的 - 它会自动转义您输入的所有内容。
  • 两个都试试,raw_string = r'''/usr/bin/rsync -e /usr/bin/ssh -o BatchMode=yes -o UserKnownHostsFile="%s/%s" -i " %s/%s" %s@%s:%s "%s/%s"''' % (basePath, self.__knownHostsPathName, basePath, self.__certPathName, self.__srcUser, self.__srcHost, srcPath, basePath, dstPath)
  • raw_string = r'/usr/bin/rsync -e /usr/bin/ssh -o BatchMode=yes -o UserKnownHostsFile=%s/%s -i %s/%s %s@ %s:%s "%s/%s"' % (basePath, self.__knownHostsPathName, basePath, self.__certPathName, self.__srcUser, self.__srcHost, srcPath, basePath, dstPath)
  • 非常感谢 Joao 的帮助,但是:我一直在获取“命令行第 0 行:行尾垃圾”。
猜你喜欢
  • 2015-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-02
  • 1970-01-01
相关资源
最近更新 更多