saber esta ejecutar ejecutando desde corriendo como comandos python subprocess

esta - ejecutar python desde cmd



Imprime constantemente la salida del subproceso mientras el proceso se está ejecutando (7)

@tokland

intenté tu código y lo corrigí para 3.4 y windows dir.cmd es un simple comando dir, guardado como archivo cmd

import subprocess c = "dir.cmd" def execute(command): popen = subprocess.Popen(command, stdout=subprocess.PIPE,bufsize=1) lines_iterator = iter(popen.stdout.readline, b"") while popen.poll() is None: for line in lines_iterator: nline = line.rstrip() print(nline.decode("latin"), end = "/r/n",flush =True) # yield line execute(c)

Para lanzar programas desde mi Python-scripts, estoy usando el siguiente método:

def execute(command): process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = process.communicate()[0] exitCode = process.returncode if (exitCode == 0): return output else: raise ProcessException(command, exitCode, output)

Entonces cuando Process.execute("mvn clean install") un proceso como Process.execute("mvn clean install") , mi programa espera hasta que el proceso finalice, y solo entonces obtengo el resultado completo de mi programa. Esto es molesto si estoy ejecutando un proceso que toma un tiempo para terminar.

¿Puedo permitir que mi programa escriba la salida del proceso línea por línea, sondeando la salida del proceso antes de que termine en un bucle o algo así?

** [EDIT] Lo siento, no busqué muy bien antes de publicar esta pregunta. Enhebrar es en realidad la clave. Encontré un ejemplo aquí que muestra cómo hacerlo: ** Subproceso de Python. Abrir desde un hilo


En caso de que alguien quiera leer de stdout y stderr al mismo tiempo, usando hilos, esto es lo que se me ocurrió:

import threading import subprocess import Queue class AsyncLineReader(threading.Thread): def __init__(self, fd, outputQueue): threading.Thread.__init__(self) assert isinstance(outputQueue, Queue.Queue) assert callable(fd.readline) self.fd = fd self.outputQueue = outputQueue def run(self): map(self.outputQueue.put, iter(self.fd.readline, '''')) def eof(self): return not self.is_alive() and self.outputQueue.empty() @classmethod def getForFd(cls, fd, start=True): queue = Queue.Queue() reader = cls(fd, queue) if start: reader.start() return reader, queue process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdoutReader, stdoutQueue) = AsyncLineReader.getForFd(process.stdout) (stderrReader, stderrQueue) = AsyncLineReader.getForFd(process.stderr) # Keep checking queues until there is no more output. while not stdoutReader.eof() or not stderrReader.eof(): # Process all available lines from the stdout Queue. while not stdoutQueue.empty(): line = stdoutQueue.get() print ''Received stdout: '' + repr(line) # Do stuff with stdout line. # Process all available lines from the stderr Queue. while not stderrQueue.empty(): line = stderrQueue.get() print ''Received stderr: '' + repr(line) # Do stuff with stderr line. # Sleep for a short time to avoid excessive CPU use while waiting for data. sleep(0.05) print "Waiting for async readers to finish..." stdoutReader.join() stderrReader.join() # Close subprocess'' file descriptors. process.stdout.close() process.stderr.close() print "Waiting for process to exit..." returnCode = process.wait() if returnCode != 0: raise subprocess.CalledProcessError(returnCode, command)

Solo quería compartir esto, ya que terminé con esta pregunta tratando de hacer algo similar, pero ninguna de las respuestas resolvió mi problema. ¡Espero que ayude a alguien!

Tenga en cuenta que en mi caso de uso, un proceso externo mata el proceso que Popen() .


Este PoC lee constantemente el resultado de un proceso y se puede acceder cuando sea necesario. Solo se conserva el último resultado, el resto de la salida se descarta, por lo tanto, evita que el PIPE crezca fuera de la memoria:

import subprocess import time import threading import Queue class FlushPipe(object): def __init__(self): self.command = [''python'', ''./print_date.py''] self.process = None self.process_output = Queue.LifoQueue(0) self.capture_output = threading.Thread(target=self.output_reader) def output_reader(self): for line in iter(self.process.stdout.readline, b''''): self.process_output.put_nowait(line) def start_process(self): self.process = subprocess.Popen(self.command, stdout=subprocess.PIPE) self.capture_output.start() def get_output_for_processing(self): line = self.process_output.get() print ">>>" + line if __name__ == "__main__": flush_pipe = FlushPipe() flush_pipe.start_process() now = time.time() while time.time() - now < 10: flush_pipe.get_output_for_processing() time.sleep(2.5) flush_pipe.capture_output.join(timeout=0.001) flush_pipe.process.kill()

print_date.py

#!/usr/bin/env python import time if __name__ == "__main__": while True: print str(time.time()) time.sleep(0.01)

salida: se puede ver claramente que solo hay salida del intervalo de ~ 2,5 s nada en el medio.

>>>1520535158.51 >>>1520535161.01 >>>1520535163.51 >>>1520535166.01


Ok, logré resolverlo sin hilos (se aprecia cualquier sugerencia de por qué usar hilos sería mejor) usando un fragmento de esta pregunta. Interceptando la salida estándar de un subproceso mientras se está ejecutando.

def execute(command): process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Poll process for new output until finished while True: nextline = process.stdout.readline() if nextline == '''' and process.poll() is not None: break sys.stdout.write(nextline) sys.stdout.flush() output = process.communicate()[0] exitCode = process.returncode if (exitCode == 0): return output else: raise ProcessException(command, exitCode, output)


Para cualquiera que intente las respuestas a esta pregunta para obtener el stdout de un script de Python, tenga en cuenta que Python almacena temporalmente su stdout y, por lo tanto, puede llevar un tiempo ver el stdout.

Esto puede rectificarse agregando lo siguiente después de cada escritura de stdout en el script de destino:

sys.stdout.flush()


Para imprimir el subproceso ''salida línea por línea tan pronto como se vacía su búfer stdout en Python 3:

from subprocess import Popen, PIPE, CalledProcessError with Popen(cmd, stdout=PIPE, bufsize=1, universal_newlines=True) as p: for line in p.stdout: print(line, end='''') # process line here if p.returncode != 0: raise CalledProcessError(p.returncode, p.args)

Aviso: no necesita p.poll() - el ciclo finaliza cuando se alcanza eof. Y no necesita iter(p.stdout.readline, '''') - el error de lectura anticipada está arreglado en Python 3.

Ver también, Python: leer la entrada de transmisión desde subprocess.communicate () .


Puede usar iter para procesar líneas tan pronto como el comando las lines = iter(fd.readline, "") : lines = iter(fd.readline, "") . Aquí hay un ejemplo completo que muestra un caso de uso típico (gracias a @JF Sebastian por ayudar):

from __future__ import print_function # Only Python 2.x import subprocess def execute(cmd): popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) for stdout_line in iter(popen.stdout.readline, ""): yield stdout_line popen.stdout.close() return_code = popen.wait() if return_code: raise subprocess.CalledProcessError(return_code, cmd) # Example for path in execute(["locate", "a"]): print(path, end="")