在Python中使用SSH
我需要通过SSH用Python连接到其他服务器,执行一些命令,并把每个命令的结果赋值给不同的变量。
最简单的方法是什么呢?
我试过SSHController,但是我觉得我在提示符上搞错了什么,导致脚本一直在等待。
如果能给我一些例子,我会非常感激。
1 个回答
在Python中使用SSH有几种方法。一般来说,主要有以下几种方式:
- 使用subprocess.Popen()等方法调用本地的
ssh
命令(这种方法适合批量获取结果) - 使用pexpect或类似的伪终端控制机制来调用和控制本地的
ssh
命令(这种方法适合在终端会话中自动启动和交互处理进程) - 使用像Paramiko或Twisted conch这样的Python模块/库,它们实现了SSH协议(要么直接用Python编写,要么提供对某些底层共享库的绑定,比如.so或DLL)。
SSHController属于第二种方法。而我自己写的工具classh则属于第一种。
你的问题表明,你可能更适合使用Paramiko,因为听起来你想根据远程进程执行的结果来设置本地变量状态。我猜测你不想把本地终端输出或错误信息和远程命令的结果混在一起。
换句话说,你想把SSH当作一个API来用,而不是把ssh
当作一个命令工具。这是一个很重要的区别。
ssh
命令尽量做到透明,和UNIX(以及类似的MS Windows等)环境相适应。ssh
会打开一个与远程系统的连接,并创建多个通道来进行远程作业的执行。因此,本地的ssh
的stdout将来自远程命令的stdout,而本地的ssh
的stderr则会混合远程的stderr和ssh
命令自身的错误信息(还有其他输出,比如你在ssh
命令中添加-v或--verbose选项时看到的调试信息)。同样,ssh
命令的退出状态通常会反映远程shell的退出状态。但是,它也可能是本地ssh
进程因本地错误而产生的退出代码——根据我的经验,这个值通常是255。我不知道有什么方法可以区分远程命令的退出值255和本地进程的“异常结束”(abend)——我怀疑没有任何便携的、标准的方法可以做到这一点。
我想说的是,从你的代码中使用ssh
命令会使你无法将本地进程(ssh
命令本身,可能还有本地shell)产生的输出与远程进程(以及可能运行该远程进程的shell)产生的输出分开。ssh
并不是一个API。
另一方面,如果你使用像Paramiko这样的工具,你就可以通过SSH协议建立一个会话,并且可以多次使用这个会话来执行命令、传输文件、进行其他文件系统操作和创建隧道。
在这种情况下,你会创建一个SSHClient
实例,并为每个想要在远程主机上执行的命令调用它的.exec_command()
方法。这在概念上类似于进行本地函数调用……如果由于某种原因无法执行该命令,它会抛出一个异常……而你从它的stdout或stderr中得到的任何结果都不会与任何中间进程(比如ssh
命令……在这种情况下根本没有被执行)产生的输出混淆。
这就是我推荐这种方法的原因。听起来你想在每个远程目标上执行几个独立的命令,而不想因为在一次调用ssh
命令中运行它们而引发的复杂问题,也不想因为多次调用ssh
而带来的复杂性和性能开销。如果你能建立一个会话并将其用作API,你的代码会更简单、更稳健。