【问题标题】:Python paramiko: redirecting stderr is affected by get_pty = TruePython paramiko:重定向stderr受get_pty = True影响
【发布时间】:2017-01-18 16:09:36
【问题描述】:

我正在尝试实现一个 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()

如果数据已缓冲并准备好从此通道的 stderr 流中读取,则返回 true。 仅使用 exec_command 或 没有 pty 的 invoke_shell 将永远在 stderr 流上有数据
返回:如果此通道上的 recv_stderr 调用将立即返回至少一个字节,则为真;否则为假。

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

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

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

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

【问题讨论】:

    标签: python ssh paramiko stderr io-redirection


    【解决方案1】:

    假设您在 *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()
        ...
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 2021-05-21
      • 2021-06-29
      • 1970-01-01
      • 2021-03-25
      • 2018-06-28
      • 2022-06-28
      相关资源
      最近更新 更多