如何从 Python 中的子进程向 SSH 传递命令
Posted
技术标签:
【中文标题】如何从 Python 中的子进程向 SSH 传递命令【英文标题】:How to pass commands to an SSH from subprocess in Python 【发布时间】:2017-08-06 12:06:54 【问题描述】:我在 Python 2.7.6 中使用了subprocess
模块来建立 SSH。我意识到不建议这样做,但我无法安装其他 Python SSH 库,例如 paramiko 和 fabric。
我只是想知道是否有人不介意告诉我现在该怎么做
sshProcess = subprocess.call(['ssh', '-t', '<REMOTE>', 'ssh', '<REMOTE>'])
我想用子进程方法在REMOTE
中执行命令。有没有办法做到这一点?不幸的是,REMOTE
受用户手动输入的密码保护。如果有帮助,我正在运行 Windows 10 Bash shell。
感谢任何帮助。
【问题讨论】:
至少,您应该区分<REMOTE>
和<COMMAND>
。你如何构建COMMAND
也很重要——如果你用变量代替而不是运行一个常量命令,那么就会出现安全问题。
...你的标题说你的问题是“如何传递命令”,但目前唯一明显你不知道如何做的部分是传递密码。您正在尝试做什么:形成要运行的远程命令,以及它是如何失败的,这很重要。
您的 Python 程序是否在用户所在的 TTY 上运行并能够以交互方式输入密码也很重要。
@CharlesDuffy 感谢您的回复。是的,用户正在交互输入密码。我才意识到我的问题措辞很糟糕。基本上,我能够很好地建立连接。但是现在我试图在用户输入他们的身份验证详细信息后自动将命令传递到该 ssh。
一种选择是为用户设置无密码登录,这样就不需要密码。这是通过在客户端生成密钥然后在服务器上更新密钥来完成的。对于 unixy 系统,这是通过 ssh-keygen
和 ssh-copy-id
完成的,但您必须弄清楚您的 ssh
客户端是如何做到的。
【参考方案1】:
运行远程命令就像将它放在命令行上一样简单。 (这对于 SSH 服务器在协议级别上与在标准输入上提供它是有区别的,但是所讨论的协议是为编程使用而构建的,而不是为人类使用而构建的——因为后者是交互式 shell 模型背后的设计意图) .
顺便说一句,如果您想在验证一次后通过不同的 SSH 调用在单个连接上运行多个命令,我强烈建议您使用 Paramiko,但您可以这样做使用 SSH multiplexing support 的 OpenSSH 命令行工具。
假设您有一个表示远程命令的数组:
myCommand = [ 'ls', '-l', '/tmp/my directory name with spaces' ]
要将其转换为字符串(以尊重空格的方式并且不能让恶意选择的名称在远程服务器上运行任意命令),您可以使用:
myCommandStr = ' '.join(pipes.quote(n) for n in myCommand)
现在,您可以将一些东西作为命令行参数传递给 ssh:
subprocess.call(['ssh', '-t', hostname, myCommandStr])
但是,假设您想嵌套它。你可以重复这个过程:
myCommand = [ 'ssh', '-t', hostname1, myCommandStr ]
myCommandStr = ' '.join(pipes.quote(n) for n in myCommand)
subprocess.call(['ssh', '-t', hostname2, myCommandStr])
因为我们没有重定向标准输入或标准输出,它们仍应指向启动 Python 程序的终端,因此 SSH 应该能够直接执行其密码提示。
也就是说,特别对于通过临时系统进行 ssh'ing,您不需要经历这么多麻烦:您可以告诉 ssh
使用 @ 为您完成这项工作987654327@选项:
myCommand = [ 'ls', '-l', '/tmp/my directory name with spaces' ]
myCommandStr = ' '.join(pipes.quote(n) for n in myCommand)
subprocess.call(['ssh', '-o', 'ProxyJump=%s' % hostname1, hostname2, myCommandStr])
【讨论】:
【参考方案2】:根据您的评论,您说可以连接。因此,在那之后,要使用子进程通过 ssh 进行交互,您将需要以下内容:
ssh = subprocess.Popen(['ssh', <remote client>],
stdin=subprocess.PIPE,
stdout = subprocess.PIPE)
back = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print error
else:
print back
然后发送命令,比如列表目录,比如:
ssh.stdin.write("ls\n")
【讨论】:
ssh.stdout.readlines()
将永远挂起,除非 stdout 关闭(此后您将无法阅读更多内容)。
...另外,走这条路意味着 SSH 进程不再有 TTY 上的句柄(因为你用管道覆盖它),所以它不能直接提示输入密码。 以上是关于如何从 Python 中的子进程向 SSH 传递命令的主要内容,如果未能解决你的问题,请参考以下文章
用python多进程模块multiprocessing创建的子进程如何共享内存空间?