2017-10-05 80 views
1

我試圖通過python的子進程和ssh運行各種linux命令。我希望能夠運行該命令並檢查stderrstdout長度以確定命令是否成功。例如,如果沒有錯誤,它是成功的。問題是,在初始連接之後,所有的輸出都是stdoutPython子進程(不正確?)合併stderr和標準輸出爲ssh

我嘗試使用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 

,其輸出是這樣的:

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。

如果你想分開遠程系統上的兩個流,你必須通過將其中一個或兩個重定向到一個遠程文件然後讀取這些文件。或者不太可靠,但可能更容易,您可以將stderr重定向到每行開始處放置類似'STDERR:'的過濾器,然後再以這種方式分割流。

+0

謝謝@Duncan。你的回答是正確的 我已經進一步瞭解了paramiko爲什麼返回'stderr',並且原來的發佈代碼沒有。我已經瞭解到,使用'ssh hostname命令'結構將會返回,就像命令是在本地運行一樣。在這種情況下,返回碼和'stderr'和'stdout'都是可訪問的。 在原始代碼中,我嘗試打開一個ssh shell,然後通過shell將命令傳遞給遠程系統。正如鄧肯指出的那樣行不通。 最終的解決方案是學會正確使用subprocess.call() – shedfly

相關問題