通过管道将 ssh 会话传入和传出 python

Pipe ssh session into and out of python

我工作的公司使用陈旧的信息系统(版权 1991-2001)。该系统是一台 Centos 机器 运行ning 一个 ssh 服务器。无法以任何方式访问后端或其数据。所有数据都需要通过文本报告检索,或通过手动按键输入。这是您登录时获得的视图的 example。

我正在尝试编写一个 python 脚本来模拟 运行 报告的击键并执行一些琐碎的任务。我已经使用 windows 上的 .cmd 文件成功完成了此操作,该文件连接并模拟击键。问题是有些进程有不可预知的分支(有时会弹出一条消息,要求提供一些信息或按键以验证您是否看到了一条消息)。我可以预测分支可能出现的位置,但无法检测它是否确实存在,因为我的 .cmd 文件无法识别来自 ssh 会话的输出。 (顺便说一句,我在 windows 工作)

我想做的是使用 python 脚本,该脚本使用 stdin 并根据它看到的内容做出决定,但我对管道的工作原理还不熟悉。通过管道传输到我的脚本中是可行的,但我不确定如何将击键从 python 脚本发送回 ssh 会话。这是我的测试脚本的示例:

import sys
import time

buff=''
try:
    while True:
        buff += sys.stdin.read(1)
        if buff[-5:] == 'press':
            print('found word "press"!')
            #Send a keystroke back to the ssh session here
            buff = ''
except KeyboardInterrupt:
    sys.stdout.flush
    pass

我是这样称呼它的:

ssh MyUsername@###.###.###.### | python -u pipe_test.py

虽然是 运行ning,但我什么也看不到,但我已经确认我可以使用我的常规键盘通过终端发送击键。

关于如何将击键输出到 ssh 会话的任何想法? 我应该做一些完全不同、更简单的事情吗?

仅供参考:服务器发送到终端的数据到处都是ASCII转义字符。这不是一个很好的 bash 界面或类似的东西。另外,我已经安装了一堆 Unix 命令行工具,这样我就可以从 windows.

ssh

tl;dr 如何从 ssh 会话通过管道传输到 python,并从同一个 python 脚本将击键发送回 ssh 会话?

绝对不能用管道来做。 Unix 管道是一种单向 inter-process 通信机制。您可以向它发送数据,也可以从它读取数据。但不是两者(通过同一个管道)。

可以使用成对的管道来创建 co-processes。这甚至在某些 Unix shell 中直接支持(例如 Korn shell 和 Bash 版本 4 (https://www.gnu.org/software/bash/manual/html_node/Coprocesses.html)。但是这种机制有些脆弱并且容易死锁。只要这对管道两侧的进程在处理管道和相关缓冲方面都严格(实际上可能只有一端是严格的,但即使这样也很棘手)。这不是您尝试远程 运行 的程序可能就是这种情况。

有人建议 pexpect 这是控制本地生成的终端或 curses 应用程序的绝佳选择。通过生成本地 ssh 客户端并控制它,可以使用它来管理远程进程。

但是,从 Python 访问 ssh 协议和 APIs 的更好选择是 Paramiko。这实现了 ssh 协议,这样你就可以像 API 一样访问远程 sshd 进程而不是通过客户端(命令行实用程序)。

这种方法的一个优点是您可以通过编程方式管理端口重定向、传输和管理文件(就像您使用 sftp 一样)(包括设置权限等),并且您可以执行程序并单独访问它们的标准输入、输出和错误流或它们的 pseudo-terminals (pty) 以及获取远程进程的退出代码,这与本地 ssh 的退出代码不同 客户。

甚至还有一个包 paramiko-expect 添加了对 Paramiko 的扩展,以便更直接地使用这些远程 pty 对象。 (Pexpect 在控制本地进程的 pty 上提供了类似的功能)。 [警告:我还没有使用过 Fotis Gimian 的软件包;但我相当广泛地使用了 Paramiko,有时希望我有类似的东西。

您可能已经从这个答案中了解到,在 Unix(Linux 或其任何变体)下以编程方式处理交互式 terminal/text 程序的复杂性与以下细节有关:该程序已编写。

一些程序,例如 shells,可以完全由面向行的输入和输出驱动到它们的标准文件描述符(stdin、stdout 和 stderr)。其他人必须通过他们的终端界面进行控制(这是通过使用 pseudo-terminal 环境启动它们来实现的...例如 sshd 在启动正常交互过程时提供的环境,以及 expect(和 pexect 以及受旧 TCL/expect[=44 启发的各种其他模块和实用程序提供的那些=]) 以及你的 xterm 或任何现代 OS 下的其他终端窗口程序(甚至包括 Cygwin 或 "Bash for Windows" 或 WSL(Windows 支持对于 Linux) 在最新版本的 Microsoft Windows) 下。

一般来说,您的尝试将需要使用一种或另一种方法,而管道仅对使用标准文件描述符的方法非常粗略有用。使用哪种方法的决定主要取决于您尝试(远程)控制的程序。