我四处搜索了很多,找到了一些我希望实现但不完全的东西。我正在制作一个同步脚本来同步两台机器之间的文件。脚本本身比这个问题更高级一些(它提供了双方请求删除文件等的可能性,没有“主方”)。
第一题
以下 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])
我希望这对想要实现我正在做的事情的人有用。
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
但这行不通,我想知道为什么。