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
调用 paramiko
的 exec_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()
...
这应该仍然允许您使用现有代码访问单独的流。
我正在尝试实现一个 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
调用 paramiko
的 exec_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()
...
这应该仍然允许您使用现有代码访问单独的流。