2017-10-05 26 views
1

私はpythonのサブプロセスとsshからさまざまなlinuxコマンドを実行しようとしています。コマンドを実行し、stderrstdoutの長さをチェックして、コマンドが成功したかどうかを確認したいと考えています。たとえば、エラーがなければ成功したとします。問題は、最初の接続後にすべての出力がstdoutになることです。Pythonのサブプロセス(間違って?)sshのstderrとstdoutをマージする

私はparamikoを使用しようとしましたが、信頼できない認証動作を続けました。このアプローチはもっとうまくいくように思えます。以下のようなものを出力

import subprocess 
import os 
import pty 
from select import select 

class open_ssh_helper(object): 
    def __init__(self, host="127.0.0.1", user="root"): 
     self.host = host 
     self.user = user 
     self.cmd = ['ssh', 
        user +'@'+host, 
        "-o", "StrictHostKeyChecking=no", 
        "-o", "UserKnownHostsFile=/dev/null"] 

     self.prompt = '~#' 
     self.error = '' 
     self.output = '' 

     self.mtty_stdin, self.stty_stdin = pty.openpty() 
     self.mtty_stdout, self.stty_stdout = pty.openpty() 
     self.mtty_stderr, self.stty_stderr = pty.openpty() 

     self.ssh = subprocess.Popen(self.cmd, 
            shell=False, 
            stdin=self.stty_stdin, 
            stdout=self.stty_stdout, 
            stderr=self.stty_stderr) 
     self._read_stderr() 
     self._read_stdout() 

    def _reader(self, read_pty): 
     char = "" 
     buf = "" 
     while True: 
      rs, ws, es = select([read_pty], [], [], 0.5) 
      if read_pty in rs: 
       char = os.read(rs[0], 1) 
       buf += char 
      else: 
       break 

     return buf 

    def _read_stderr(self): 
     self.error = self._reader(self.mtty_stderr) 

    def _read_stdout(self): 
     self.output = self._reader(self.mtty_stdout) 

    def execute(self, command): 
     os.write(self.mtty_stdin, command) 

     self._read_stderr() 
     self._read_stdout() 

if __name__=='__main__': 
    ss = open_ssh_helper('10.201.202.236', 'root') 

    print "Error: \t\t: " + ss.error 
    print "Output: \t: " + ss.output 

    ss.execute("cat /not/a/file\n") 

    print "Error: \t\t: " + ss.error 
    print "Output: \t: " + ss.output 

:エラー行として印刷されるそのようなファイルやディレクトリ:/ない/ A /ファイル:

Error:  : Warning: Permanently added '10.201.202.236' (ECDSA) to the list of known hosts. 
Debian GNU/Linux 8 
BeagleBoard.org Debian Image xxxx-xx-xx 
Support/FAQ: http://elinux.org/Beagleboard:BeagleBoneBlack_Debian 

Output:  : Last login: Thu Oct 5 07:32:06 2017 from 10.201.203.29 
[email protected]:~# 
Error:  : 
Output:  : cat /not/a/file 
cat: /not/a/file: No such file or directory 
[email protected]:~# 

私の希望は、ライン猫ということでしたその上に。しかし、何らかの理由でstdoutが出力とエラーの両方を出力しているようです。

答えて

1

sshは、リモートシステム上のstdoutとstderrの両方を単一のストリームとしてプルバックするので、両方ともssh stdoutに入ります。

リモートシステム上の2つのストリームを分離したい場合は、一方または両方のリダイレクトをリモートファイルにリダイレクトしてからファイルを読み込む必要があります。より信頼性は低いがおそらく簡単に、stderrを、各行の先頭に 'STDERR:'のようなものを置くフィルタを介してリダイレクトし、再びその流れを分割することができます。

+0

ありがとう@Duncan。あなたの答えは正しい 私はparamikoが 'stderr'を返す理由をさらに調べました。私は、 'ssh hostname command'構造体を使用すると、コマンドがローカルで実行されたかのように戻ることを知りました。その場合、リターンコードと 'stderr'と' stdout'はすべてアクセス可能です。 元のコードでは、sshシェルを開き、シェル経由でリモートシステムにコマンドを渡そうとしました。ダンカンが指摘したように、それはうまくいきません。 究極の解決策は、subprocess.call()を正しく使用することを学ぶことでした – shedfly

関連する問題