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

so.*_*red 5 python ssh paramiko stderr io-redirection

我正在尝试实现一个 ssh 代理,除其他外,它允许我稍后在阻塞模式下执行命令,在该模式下,只要输出可用,就会从通道中读取输出。
\n这是我到目前为止所拥有的:

\n\n
from paramiko import client\n\nclass SSH_Agent:\n\n    def __init__(self, server_name, username = getpass.getuser(), password = None, connection_timeout = CONNECTION_TIMEOUT):\n        self.ssh_agent = client.SSHClient()\n        self.ssh_agent.set_missing_host_key_policy(client.AutoAddPolicy())\n        self.ssh_agent.connect(server_name, username = username, password = password if password is not None else username, timeout = connection_timeout)\n\n\n    def execute_command(self, command, out_streams = [sys.stdout], err_streams = [sys.stderr], poll_intervals = POLL_INTERVALS):\n        stdin, stdout, stderr = self.ssh_agent.exec_command(command)\n        channel = stdout.channel\n        stdin.close()\n        channel.shutdown_write()\n\n        while not channel.closed or channel.recv_ready() or channel.recv_stderr_ready():\n            got_data = False\n            output_channels = select.select([channel], [], [], poll_intervals)[0]\n\n            if output_channels:\n                channel = output_channels[0]\n                if channel.recv_ready():\n                    for stream in out_streams:\n                        stream.write(channel.recv(len(channel.in_buffer)))\n                        stream.flush()\n                    got_data = True\n\n                if channel.recv_stderr_ready():\n                    for stream in err_streams:\n                        stream.write(channel.recv_stderr(len(channel.in_stderr_buffer)))\n                        stream.flush()\n                    got_data = True\n\n            if not got_data \\\n            and channel.exit_status_ready() \\\n            and not channel.recv_ready() \\\n            and not channel.recv_stderr_ready():\n                channel.shutdown_read()\n                channel.close()\n                break\n\n        return channel.recv_exit_status()\n
Run Code Online (Sandbox Code Playgroud)\n\n

(这个实现基于我在 SO 中找到的一个)
\n当我测试它时,它工作正常,除了我在执行命令时得到这个:

\n\n
tput: No value for $TERM and no -T specified\n
Run Code Online (Sandbox Code Playgroud)\n\n

我在网上读了一些内容,发现发生这种情况是因为会话后面没有实际的终端ssh
\n所以,我尝试用paramiko以下方式exec_command()调用get_pty = True

\n\n
stdin, stdout, stderr = self.ssh_agent.exec_command(command, get_pty = True)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
\n

recv_stderr_ready()

\n\n

如果数据已缓冲并准备好从此通道\xe2\x80\x99s stderr 流读取,则返回 true。只有使用 exec_command 或不带 pty 的 invoke_shell 的通道才会在 stderr 流上有数据
\n 返回:如果此通道上的 recv_stderr 调用将立即返回至少一个字节,则返回 True;否则为假。

\n
\n\n

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

\n\n
tput: No value for $TERM and no -T specified\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n

Pet*_*ain 2

假设您在 *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()
    ...
Run Code Online (Sandbox Code Playgroud)

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