我四处搜索了很多,找到了一些我希望实现但不完整的东西。我正在制作一个同步脚本来同步两台机器之间的文件。脚本本身比这个问题更高级一些(它提供了双方请求删除文件等的可能性,没有“主方”)。
第一个问题
以下 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)。
请您参考如下方法:
我找到了一种方法来满足我自己的需要。它包括调用一个 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])
我希望这对想要实现我正在做的事情的人有用。
