我正在尝试实现一个ssh代理,它允许我稍后以阻塞模式执行命令,在这种模式下,一旦输出可用,就会从通道中读取。
以下是我目前所掌握的情况:from paramiko import client
class SSH_Agent:
def __init__(self, server_name, username = getpass.getuser(), password = None, connection_timeout = CONNECTION_TIMEOUT):
self.ssh_agent = client.SSHClient()
self.ssh_agent.set_missing_host_key_policy(client.AutoAddPolicy())
self.ssh_agent.connect(server_name, username = username, password = password if password is not None else username, timeout = connection_timeout)
def execute_command(self, command, out_streams = [sys.stdout], err_streams = [sys.stderr], poll_intervals = POLL_INTERVALS):
stdin, stdout, stderr = self.ssh_agent.exec_command(command)
channel = stdout.channel
stdin.close()
channel.shutdown_write()
while not channel.closed or channel.recv_ready() or channel.recv_stderr_ready():
got_data = False
output_channels = select.select([channel], [], [], poll_intervals)[0]
if output_channels:
channel = output_channels[0]
if channel.recv_ready():
for stream in out_streams:
stream.write(channel.recv(len(channel.in_buffer)))
stream.flush()
got_data = True
if channel.recv_stderr_ready():
for stream in err_streams:
stream.write(channel.recv_stderr(len(channel.in_stderr_buffer)))
stream.flush()
got_data = True
if not got_data \
and channel.exit_status_ready() \
and not channel.recv_ready() \
and not channel.recv_stderr_ready():
channel.shutdown_read()
channel.close()
break
return channel.recv_exit_status()
(此实现基于我在SO中找到的一个)
当我测试它时,它工作得很好,除了我在执行命令时得到的结果是:
^{pr2}$
我在网上读了一点,发现这是因为ssh会话后面没有实际的终端。
所以,我试着用get_pty = True调用paramiko的exec_command():stdin, stdout, stderr = self.ssh_agent.exec_command(command, get_pty = True)
但后来我发现我失去了向通道上的stderr获取数据的能力(由于某些原因,所有的东西都流向{},即{}永远不是{})。事实上,我在文件中发现了以下内容:recv_stderr_ready()
Returns true if data is buffered and ready to be read from this channel’s stderr stream. Only channels using exec_command or
invoke_shell without a pty will ever have data on the stderr stream.
Returns: True if a recv_stderr call on this channel would immediately return at least one byte; False otherwise.
我怎么能两者兼得?
换言之,我怎样才能摆脱这个问题:
^{pr2}$
同时还能将stderr指向我选择的任何地方?在
编辑:
我刚有个主意…
我能在远程shell中定义这个TERM变量来消除这个错误吗?这是一种常见的方法还是一种只隐藏问题的糟糕解决方法?在