2016-09-10 7 views
1

블로킹 모드에서 명령을 실행할 수있게 해주는 ssh 에이전트를 구현하려고합니다. 출력은 채널에서 즉시 읽혀집니다. 사용할 수 있습니다.Python paramiko : stderr 리다이렉트는 get_pty = True의 영향을받습니다.

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 세션 뒤에 실제 단자가 없기 때문에 그런 일이 발견.
그래서 내가 전화를 시도 paramikoexec_command() get_pty = True과 :

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

그러나 나는 모든 것을 어떤 이유로 stdout로 이동 (채널에 stderr에 대한 데이터를 얻을 수있는 능력을 잃고 있다는 것을 발견 즉 channel.recv_stderr_ready()은 결코 True이 아닙니다.

recv_stderr_ready() 데이터 버퍼링되고있는 경우는 true 준비

반환은이 채널의 표준 오류 스트림에서 읽을 수 : 사실, 나는 다음 문서에서 발견. pty가없는 exec_command 또는 invoke_shell을 사용하는 채널 만 stderr 스트림에 대한 데이터를 갖습니다.
반환 값 :이 채널의 recv_stderr 호출로, 적어도 1 바이트는 즉시 리턴되는 경우는 true. 그렇지 않으면 거짓.

어떻게 둘 다 가질 수 있습니까? 즉
는 어떻게이 제거 할 수 있습니다

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

아직도 내가 선택 어디든지 stderr를 지시 할 수있는 능력을 가지면서?

편집 :
내가 그냥 생각이 ...
내가 어떻게 든 원격 셸이 TERM 변수를 정의 할 수 있었다 그 오류를 제거하려면? 이 방법이 일반적인 방법입니까 아니면 문제를 숨기는 유일한 방법일까요?

답변

2

* nix 시스템에서 실행 중이라고 가정하면 pty를 작성하는 대신 명령 환경에서 TERM을 설정할 수 있습니다. 예를 들어

:

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() 
    ... 

이 여전히 기존 코드를 사용하여 별도의 스트림에 액세스 할 수 있도록해야한다.

+0

좋습니다. 그것은 트릭을했다. –