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

问题描述 投票:0回答:2

我四处搜索了很多,找到了一些我希望实现但不完全的东西。我正在制作一个同步脚本来同步两台机器之间的文件。脚本本身比这个问题更高级一些(它提供了双方请求删除文件等的可能性,没有“主方”)。

第一题

以下 bash 命令对我有用:

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 次登录。

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

我是否仍然以错误的方式推理这个?我可以做些什么来加强所用密码的完整性吗?我已经意识到我应该抑制来自 subprocess 模块的错误,因为它可能会显示带有密码的命令。

非常感谢对问题的任何了解!

编辑:

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

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

python subprocess port rsync
2个回答
3
投票

我找到了一种方法来满足我自己的需要。它包括调用一个 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 命令,以下 python 应该执行:

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

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


0
投票

TLDR

使用

sshpass -f /path/to/your/password/file

代替-p选项。

这条线下我的尝试和问题

我在 2023 年遇到这个问题,比你晚了 9 年。 原因可能来自您的密码

sshpass -p pw

我仍然不明白 python 如何处理这个 pw var,但它似乎与 bash shell 有点不同。

我试过了

sshpass -p

cat /home/lee/.password

但这行不通,我想知道为什么。

© www.soinside.com 2019 - 2024. All rights reserved.