Python paramiko:重定向 stderr 受 get_pty = True 影响

Python paramiko: redirecting stderr is affected by get_pty = True

我正在尝试实现一个 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 中某处找到的实现)
当我测试它时,它工作正常,除了我在执行命令时得到这个:

tput: No value for $TERM and no -T specified

我在网上看了一点,发现发生这种情况是因为 ssh 会话后面没有实际的终端。
所以,我尝试用 get_pty = True 调用 paramikoexec_command()

stdin, stdout, stderr = self.ssh_agent.exec_command(command, get_pty = True)

但后来我发现我失去了在频道上获取数据到 stderr 的能力(由于某种原因,所有内容都转到 stdout,即 channel.recv_stderr_ready() 永远不会True)。事实上,我在文档中发现了以下内容:

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.

我怎样才能两者兼得?
换句话说,我怎样才能摆脱这个:

tput: No value for $TERM and no -T specified

同时仍然能够将 stderr 定向到我选择的任何地方?

编辑:
我刚刚有个想法...
我能否以某种方式在远程 shell 中定义此 TERM 变量以消除该错误?这是一种常见的方法还是只是隐藏问题的糟糕解决方法?

假设您 运行 在 *nix 系统上,您可以尝试在命令环境中设置 TERM 而不是创建 pty。

例如:

def execute_command(self, command, out_streams = [sys.stdout], err_streams = [sys.stderr], poll_intervals = POLL_INTERVALS):
    # Pre-pend required environment here
    command = "TERM=xterm " + command
    stdin, stdout, stderr = self.ssh_agent.exec_command(command)
    channel = stdout.channel
    stdin.close()
    channel.shutdown_write()
    ...

这应该仍然允许您使用现有代码访问单独的流。