打电话子流程.Popenstdin、stdout和stderr设置为子流程.管道改变终端的行为

2024-09-30 18:13:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近开发了一个Python脚本来利用一个工具通过JMX从jvm中检索度量。父进程(p1)使用以下代码启动另一个进程(p2)。在

p2 = subprocess.Popen(
    ['java', '-jar', '/path/to/jmxterm-1.0-alpha-4-uber.jar',
     '-l', url, '-u', username, '-p', password],
    stdin = subprocess.PIPE,
    stdout = subprocess.PIPE,
    stderr = subprocess.PIPE)

一旦p2启动并运行,p1将进入一个非常长的循环,在该循环中它将执行以下三个操作:

  1. 睡眠10秒
  2. 通过调用p2.stdin.write(),向p2发送查询
  3. 通过调用p2.stdout.readline()读取结果。在

问题:

  1. 我的剧本如预期的那样工作直到它退出。如果我按Ctrl+C停止p1并返回到终端,一切正常。如果我等到p1完成长循环并退出,终端工作正常,只是我输入的所有字符都看不见了。例如,如果我输入'ls',屏幕上什么也看不到。但是当我点击Return时,我仍然可以看到像往常一样列出的文件和子目录。我的问题是,幕后会发生什么?在
  2. 如果我删除stderr = subprocess.PIPE,那么jmxterm打印到stderr的帮助消息将转到终端。因为他们弄乱了我脚本的输出,所以我试图改变

    ^{pr2}$

    ['java', '-jar', '/path/to/jmxterm-1.0-alpha-4-uber.jar', '-l', url,
             '-u', username, '-p', password, '2>/dev/null']
    

    但是什么都没有改变(帮助信息仍然发送到终端)。然后,我将stderr = subprocess.PIPE添加回我的脚本,并启动一个守护进程线程从stderr读取,并丢弃它读取的任何内容。令我惊讶的是,守护进程线程没有从stderr读取任何内容。我完全迷路了。如果你有线索,请帮我一把。

代码粘贴在下面以供参考:

from Queue import Queue

class JmxD(Detector):

    def __init__(self, myId, jmxUrl, username, password):
        super(JmxD, self).__init__(myId)

        self.__jmxUrl = jmxUrl
        self.__username = username
        self.__password = password

        # Start JMX terminal
        self.__jmxTerm = subprocess.Popen(
            ['java', '-jar', jmxTermPath,
             '-l', jmxUrl, '-u', username, '-p', password],
            stdin = subprocess.PIPE,
            stdout = subprocess.PIPE,
            stderr = subprocess.PIPE)

        # Start two daemon threads to read from JMX terminal's stdout & stderr
        def _stream2Queue(out, queue):
            for line in iter(out.readline, ''):
                line = line.strip()
                if line:
                    queue.put(line)
            out.close()

        def _stream2Null(out):
            for line in iter(out.readline, ''):
                #print 'A line read from stderr: %s' % line.strip()
                pass
            out.close()

        self.__queue = Queue()
        self.__reader = Thread(target=_stream2Queue,
                               args=(self.__jmxTerm.stdout, self.__queue))
        self.__reader.setDaemon(True) # This thread dies with the program
        self.__reader.start()

        self.__discarder = Thread(target=_stream2Null,
                                  args=(self.__jmxTerm.stderr))
        self.__discarder.setDaemon(True) # This thread dies with the program
        self.__discarder.start()

Tags: self终端进程stderrstdoutlineusernamepassword