调用subprocess.Popen并将stdin,stdout和stderr设置为subprocess.PIPE更改终端的行为

时间:2013-05-15 17:25:14

标签: python subprocess pipe popen

我最近开发了一个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;
  3. p2.stdin.write()发送查询
  4. 通过调用p2.stdout.readline()来读取结果。
  5. 问题:

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

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

      ['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中读取任何内容。我完全迷失了。如果你有线索,请帮我一把。

    3. 供您参考,代码粘贴在下面:

      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()
      

0 个答案:

没有答案