2017-10-05 82 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

相关问题