Python子进程rsync使用sshpass并指定端口

时间:2014-01-27 11:04:11

标签: python subprocess port rsync

我已经搜索了很多,找到了我希望实现但未完全实现的内容。我正在制作一个sync-script来同步两台机器之间的文件。脚本本身比这个问题更先进(它提供了双方请求删除文件的可能性等等,没有“主方”)。

第一个问题

以下bash-command对我有用:

rsync -rlvptghe 'sshpass -p <password> ssh -p <port>' <source> <destination>

如何将其转换为与子进程对象一起使用的python命令?

我设法让以下python工作:

pw = getpass.getpass("Password for remote host: ")
command = ['sshpass', '-p', pw, 'rsync', '-rlvptgh', source, destination]
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while p.poll() is None:
   out = p.stdout.read(1)
   sys.stdout.write(out)
   sys.stdout.flush()

但它没有指定端口(它使用标准22,我想要另一个)。为了澄清,我希望使用与此类似的代码,但也支持特定端口。

我已经尝试将命令更改为:

command = ['sshpass', '-p', pw, 'rsync', '-rlvptghe', 'ssh', '-p', '2222', source, destination]

会出现以下错误:

ssh: illegal option -- r

以及许多其他变体,例如:

command = ['rsync', '-rlvptghe', 'sshpass', '-p', pw, 'ssh', '-p', '2222', source, destination]

其中出现以下错误(其中<source>是要从中同步的远程主机源主机,即命令声明上方的变量源):

Unexpected remote arg: <source>

我应该如何根据我的第一个bash命令指定此命令来嵌套它们?

第二个问题

当我完成所有搜索后,我发现使用包含scp / rsync密码(即ssh)的命令时会发现很多皱眉,我在脚本中使用了该密码。我的理由是,在进行同步时,我希望提示输入密码。它是手动完成的,因为它提供了有关文件系统修改和其他内容的反馈。但是,由于我做了2个scp和2个rsync调用,我不想输入相同的密码4次。这就是为什么我使用这种方法让python(getpass模块)一次收集密码然后用于所有4次登录。

如果脚本计划用于自动设置,我当然会使用证书,我不会将密码以明文形式保存在文件中。

我还在推理这个错误的方法吗?我有什么办法可以加强所用密码的完整性吗?我已经意识到我应该抑制来自子进程模块的错误,因为它可能会显示带有密码的命令。

对这个问题的任何启发都非常感谢!

修改

我已经更新了问题1,并提供了更多关于我所追求的信息。我还纠正了python代码中的次要复制+粘贴错误。

编辑2进一步解释说我确实尝试了与第一个bash命令完全相同的顺序。那是我第一次尝试。它不起作用。更改订单的原因是因为它与另一个订单(sshpass优先)一起工作而没有指定端口。

1 个答案:

答案 0 :(得分:1)

我找到了一种方法来满足自己的需求。它包括调用一个shell来处理命令,这是我首先避免的。虽然它适用于我,但可能不会令其他人满意。这取决于你想要运行命令的环境。对我来说,这或多或少是bash shell的扩展,我想做一些在python中更容易的事情,同时运行一些bash命令(scp)和rsync)。

我会等待一段时间,如果没有比这更好的解决方案,我会将答案标记为答案。

使用密码和端口通过python运行rsync的基本功能可以是:

def syncFiles(pw, source, destination, port, excludeFile=None, dryRun=False, showProgress=False):
    command = 'rsync -rlvptghe \'sshpass -p ' + pw + ' ssh -p ' + port + '\' ' + source + ' ' + destination
    if excludeFile != None:
        command += ' --exclude-from='+excludeFile
    if dryRun:
        command += ' --dry-run'
    if showProgress:
        command += ' --progress'
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
    while p.poll() is None:
        out = p.stdout.read(1)
        sys.stdout.write(out)
        sys.stdout.flush()

这个工作的原因与我写的一样,因为调用的bash shell会处理命令。这样我就可以像在shell中直接编写命令一样。如果没有shell=True,我仍然不知道如何做到这一点。

请注意,密码是使用getpass模块从用户处收集的:

pw = getpass.getpass("Password for current user on remote host: ")

建议不要将密码存储在python文件或任何其他文件中。如果您正在寻找自动化解决方案,最好使用私钥。可以通过搜索找到此类解决方案的答案。

要使用密码调用scp-command,以下python应该执行:

subprocess.check_output(['sshpass', '-p', pw, 'scp', '-P', port, source, destination])

我希望这对想要实现我正在做的事情的人有用。