Python SSH通过Pseudo TTY C

2024-05-19 00:23:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我编写了以下python模块来处理程序中的ssh连接:

#!/usr/bin/env python
from vxpty import VX_PTY

class SSHError(Exception):
  def __init__(self, msg):
    self.msg = msg
  def __str__(self):
    return repr(self.msg)

class SSHShell:
  def __init__(self, host, port, user, password):
    self.host = host
    self.port = port
    self.user = user
    self.password = password
    self.authenticated = False
  def authenticate(self):
    self.tty = VX_PTY(['/usr/bin/ssh', 'ssh', '-p'+str(self.port), self.user+'@'+self.host])
    resp = self.tty.read()
    if "authenticity of host" in resp:
      self.tty.println('yes')
      while 1:
        resp = self.tty.read()
        if "added" in resp:
          break
      resp = self.tty.read()
    if "assword:" in resp:
      self.tty.println(self.password)
      tmp_resp = self.tty.read()
      tmp_resp += self.tty.read()
      if "denied" in tmp_resp or "assword:" in tmp_resp:
        raise(SSHError("Authentication failed"))
      else:
        self.authenticated = True
        self.tty.println("PS1=''")
    return self.authenticated
  def execute(self, os_cmd):
    self.tty.println(os_cmd)
    resp_buf = self.tty.read().replace(os_cmd+'\r\n', '')
    return resp_buf

它使用了我之前编写的pty模块:

^{pr2}$

但是,每当我调用execute()方法时,我都会从第一行读取输出:

>>> import SSH;shell=SSH.SSHShell('localhost',22,'735tesla','notmypassword');shell.authenticate()
True
>>> shell.execute('whoami')
"\x1b[?1034hLaptop:~ 735Tesla$ PS1=''\r\n"
>>>

第二次调用read()时,我得到了输出:

>>> shell.tty.read()
'whoami\r\n735Tesla\r\n'
>>> 

从输出中删除whoami\r\n不是问题,但是有没有方法可以清除输出,这样我就不必在第一个命令中调用read两次了?在


Tags: inselfhostreadifportdefmsg
1条回答
网友
1楼 · 发布于 2024-05-19 00:23:15

我认为你的问题比你意识到的更深。幸运的是,它比你想象的要容易解决。在

您似乎希望os.read在一次调用中返回shell必须发送给您的全部内容。这不是你可以要求的。取决于几个因素,包括但不限于shell的实现、网络带宽和延迟,以及pty(您和远程主机的)的行为,每次调用read时返回的数据量可以是所有数据量,也可以是一个字符。在

如果您只想接收命令的输出,就应该用唯一的标记将其括起来,不要担心会弄乱PS1。我的意思是,您需要在命令执行之前使shell输出成为唯一的字符串,在命令执行之后再输出另一个字符串。然后,tty.read方法应该返回它在这两个标记字符串之间找到的所有文本。使shell输出这些唯一字符串的最简单方法就是使用echo命令。在

对于多行命令,必须将命令包装在shell函数中,并在执行函数之前和之后回显标记。在

一个简单的实现如下:

def execute(self, cmd):
    if '\n' in cmd:
        self.pty.println(
            '__cmd_func__(){\n%s\n' % cmd +
            '}; echo __"cmd_start"__; __cmd_func__; echo __"cmd_end"__; unset -f __cmd_func__'
        )
    else:
        self.pty.println('echo __"cmd_start"__; %s; echo __"cmd_end"__' % cmd)

    resp = ''
    while not '__cmd_start__\r\n' in resp:
        resp += self.pty.read()

    resp = resp[resp.find('__cmd_start__\r\n') + 15:] # 15 == len('__cmd_start__\r\n')

    while not '_cmd_end__' in resp:
        resp += self.pty.read()

    return resp[:resp.find('__cmd_end__')]

相关问题 更多 >

    热门问题