在 python 中使用 SSH
我需要使用 Python 通过 SSH 连接其他服务器,执行几个命令并将每个命令的结果分配给不同的变量。
最简单的方法是什么?
我已经尝试过 SSHController,但我认为,我已经搞砸了一些提示,并且脚本正在无休止地等待。
我将非常感激任何例子。
I need to connect with other server via SSH using Python, execute few comands and assign result of each command to differrent variables.
What is the simplest way to do it?
I've tried SSHController, but I think, I've screwed up something with prompt, and the script is waiting for it endlessly.
I'll be so grateful for any examples.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有多种方法可以在 Python 中使用 SSH。一般方法是:
SSHController 属于第二大类。我自己的简陋实用程序 classh 属于第一类。
您的问题表明,探索 Paramiko 可能会为您提供最好的服务,因为听起来您想设置本地基于远程进程执行结果的变量状态。我猜您不希望有任何机会将任何类型的本地终端输出或错误消息与远程命令的结果混为一谈。
换句话说,听起来您想使用 SSH 作为 API,而不是使用
ssh
作为命令实用程序。这是一个本质的区别。ssh
命令尝试在 UNIX(以及类似的 MS Windows 等)环境允许的范围内尽可能透明。ssh
打开与远程系统的连接,并创建多个远程作业执行通信的通道。因此,本地ssh
stdout 将来自远程命令的 stdout 和本地ssh
stderr< /em> 将是远程的 stderr 和任何ssh
命令自己的错误消息(以及其他输出,例如通过添加-v, --verbose 选项您的 ssh 调用)。同样,ssh
命令的退出状态通常会反映远程 shell 的退出状态。然而,它也可能是本地ssh
进程自己的本地错误退出代码 --- 根据我的经验,它似乎总是值 255。我不知道你无法区分远程命令的退出值 255 与本地进程的“异常结束”(异常进程结束)相比 --- 我怀疑没有任何可移植的标准方法可以做到这一点)。我的观点是,在代码中使用 ssh 命令必然会阻止您将输出与本地进程(
ssh
二进制文件本身,也许取决于以及如何执行它的本地 shell)以及从远程进程发出的那些(可能还有运行预期远程进程的 shell)。ssh
不是 API。另一方面,如果您使用像 Paramiko 这样的东西,那么您可以通过 SSH 协议建立一个会话,您可以使用、和重用它来执行命令、传输文件、执行一些其他文件系统功能,以及创建隧道。
在这种情况下,您创建一个
SSHClient
实例,并为要在远程主机上执行的每个命令调用其.exec_command()
方法。这在概念上类似于进行本地函数调用...如果该命令因任何原因无法执行,它将引发异常...以及从其 stdout 或 获得的任何结果stderr 不能与任何中间进程的可能输出(例如 ssh 二进制文件......在这种情况下根本不被执行)混为一谈。这就是我推荐这种方法的原因。听起来您希望在每个远程目标上执行多个单独的命令,以避免在一次调用 ssh 实用程序中运行所有命令时可能出现的复杂情况,并且不会产生复杂性和性能开销多次调用
ssh
。如果您可以建立一个会话并将其用作 API,那么听起来您的代码会更简单、更健壮。There are a number of ways to use SSH from within Python. The general approaches are:
ssh
binary using subprocess.Popen() or similar (suitable only for gathering the results in batch)ssh
binary using pexpect or a similar pty (psuedo-TTY) process control mechanism (for spawning and interacting with a process in a terminal session in an automated manner)SSHController is in the second of these broad categories. My own humble utility, classh is in the first category.
Your question suggests that you might be best served by exploring Paramiko because it sounds like you want to set local variable state based on the results from remote process execution. I'm guessing that you don't want any chance of conflating any sort of local terminal output or error messages with the remote command's results.
In other words it sounds like you want to use SSH as an API rather than
ssh
as a command utility. This is an essential distinction.The
ssh
command tries to be as transparent as the UNIX (and analogous MS Windows, etc) environments allow.ssh
opens a connection to the remote system and creates a number of channels over which remote job execution communicates. So the localssh
stdout will be from the remote commands' stdout and the localssh
stderr will be a mixture of the remote's stderr and any of thessh
command's own error messages (and other output, such as the debugging information you'd see from adding the -v, --verbose options to yourssh
invocation). Similarly thessh
command's exit status will, normally, reflect the exit status from the remote shell. However it may also be the localssh
process' own exit code from a local error --- which, in my experience, seems to always be value 255. I know of no way that you could distinguish between a remote command's exit value of 255 vs. an "abend" (abnormal process end) from the local process --- and I suspect that there is not any portable, standard way to do so).My point here is that using the
ssh
command from within your code will, necessarily, preclude you from separating the output from local processes (thessh
binary itself, and perhaps, depending on how you're executing it, a local shell for that) and those which emanated from the remote process (and perhaps the shell in which the intended remote process is running).ssh
is not an API.On the other hand if you use something like Paramiko then you establish a session over the SSH protocol and you can use, and re-use that to execute commands, transfer files, perform some other filesystem functions, and create tunnels.
In that case you create an
SSHClient
instance and call its.exec_command()
method for each command you which to execute on the remote host. This is conceptually similar to making a local function call ... it will raise an exception if the command could not be executed for any reason ... and any results you get from its stdout or stderr cannot be conflated with possible output from any intermediary processes (such as thessh
binary ... which isn't being executed at all in this case).That's why I'm recommending this approach. It sounds like you want to execute several separate commands on each remote target in a way that obviates the possible complications arising from running them all in a single call to the
ssh
utility and without the complications and performance overhead of making multiple calls tossh
. It sounds like your code will be much simpler and more robust if you can establish a session and use that as an API.