我正在编写一个使用 SSH 命令的 GUI。我尝试使用 subprocess 模块调用 ssh 并设置 SSH_ASKPASS 环境变量,以便我的应用程序可以弹出一个窗口询问 SSH 密码。但是,我无法使用给定的 SSH_ASKPASS 命令让 ssh 读取密码:它总是在终端窗口中提示它,无论我如何设置 DISPLAY、SSH_ASKPASS、TERM 环境变量或我如何通过管道传输标准输入/输出。如何确保 ssh 与当前 TTY 分离并使用给定程序读取密码?
我的测试代码是:
#!/usr/bin/env python
import os
import subprocess
env = dict(os.environ)
env['DISPLAY'] = ':9999' # Fake value (trying in OS X and Windows)
del env['TERM']
env['SSH_ASKPASS'] = '/opt/local/libexec/git-core/git-gui--askpass'
p = subprocess.Popen(['ssh', '-T', '-v', 'user@myhost.com'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env
)
p.communicate()
最佳答案
SSH 仅在进程真正脱离 TTY 时才使用 SSH_ASKPASS 变量(stdin 重定向和设置环境变量是不够的)。要从控制台分离进程,它应该 fork 并调用 os.setsid()。所以我找到的第一个解决方案是:
# Detach process
pid = os.fork()
if pid == 0:
# Ensure that process is detached from TTY
os.setsid()
# call ssh from here
else:
print "Waiting for ssh (pid %d)" % pid
os.waitpid(pid, 0)
print "Done"
还有一种使用子进程模块的优雅方法:在 preexec_fn 参数中,我们可以传递一个 Python 函数,该函数在执行外部命令之前在子进程中调用。所以问题的解决方案是多一行:
env = {'SSH_ASKPASS':'/path/to/myprog', 'DISPLAY':':9999'}
p = subprocess.Popen(['ssh', '-T', '-v', 'user@myhost.com'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
preexec_fn=os.setsid
)
关于python - 如何通过子进程模块调用 ssh 以便它使用 SSH_ASKPASS 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1787288/