Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python子进程(错误?)合并ssh的stderr和stdout_Python_Linux_Ssh_Subprocess - Fatal编程技术网

Python子进程(错误?)合并ssh的stderr和stdout

Python子进程(错误?)合并ssh的stderr和stdout,python,linux,ssh,subprocess,Python,Linux,Ssh,Subprocess,我试图通过python的子进程和ssh运行各种linux命令。我希望能够运行该命令并检查stderr和stdout长度,以确定该命令是否成功。例如,如果没有错误,它就是成功的。问题是,在初始连接之后,所有输出都将进入标准输出 我确实尝试过使用paramiko,但不断出现不可靠的身份验证行为。如果我能让它工作的话,这种方法看起来更稳健 import subprocess import os import pty from select import select class open_ssh_h

我试图通过python的子进程和ssh运行各种linux命令。我希望能够运行该命令并检查
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
其输出类似于:

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
root@beaglebone:~# 
Error:      : 
Output:     : cat /not/a/file
cat: /not/a/file: No such file or directory
root@beaglebone:~# 

我的希望是,cat:/not/a/file行:没有这样的文件或目录会被打印为上面的错误行。然而,似乎出于某种原因,stdout正在打印输出和错误。

ssh将远程系统上的stdout和stderr作为一个流拉回来,因此它们都通过ssh stdout


如果要分离远程系统上的两个流,必须将其中一个或两个流重定向到远程文件,然后读取文件。或者更不可靠,但可能更容易,您可以通过一个过滤器重定向stderr,在每行的开头放上类似“stderr:”的内容,并以这种方式再次拆分流。

谢谢@Duncan。您的回答是正确的,我已经深入了解了为什么paramiko返回
stderr
,而最初发布的代码没有返回。我了解到,使用structure
ssh hostname命令
将返回命令,就像该命令在本地运行一样。在这种情况下,返回代码和
stderr
stdout
都可以访问。在最初的代码中,我试图打开一个ssh shell,然后通过shell将命令传递给远程系统。正如邓肯指出的那样,这是行不通的。最终的解决方案是学会正确使用subprocess.call()