2011-03-02 17 views
8

Mi script python utiliza un subproceso para llamar a otro script, que produce resultados muy lentos (línea por línea). Me gustaría escribir el resultado línea por línea en archivo no cuando todo el proceso finaliza y escribe todo el resultado como cadena. El siguiente código escribe el resultado en "archivo" cuando termina el "script".Guardar stdout del subproceso.Pobrear archivo línea por línea

args = ("script") 
file = open('output.txt', 'w') 
subprocess.Popen(args,stdout=file) 

¿Es posible? Gracias, Chris

Respuesta

1

Sí, es posible. Aquí hay una función que escribí para un uso de arnés de prueba para hacer pruebas unitarias de scripts de shell Python.

def testrun(cmdline): 
    try: 
     cmdout, cmderr = "","" 
     cmdp = Popen(cmdline, shell=True,stdout=PIPE, stderr=PIPE) 
     cmdout,cmderr = cmdp.communicate() 
     retcode = cmdp.wait() 
     if retcode < 0: 
     print >>sys.stderr, "Child was terminated by signal", -retcode 
     else: 
     return (retcode,cmdout,cmderr) 
    except OSError, e: 
     return (e,cmdout,cmderr) 

la función devuelve una tupla que contiene los problemas de código de retorno shell por sys.exit(), el texto de salida estándar, y el texto de salida de error estándar. Ambos son cadenas de texto, por lo que necesitaría usar splitlines para dividirlos en líneas antes del procesamiento.

Si realmente necesita interactuar con la salida, línea por línea, entonces probablemente sea mejor usar pexpect en lugar del módulo subprocess.

+0

¿Puede dar un ejemplo usando pexpect? – perimosocordiae

+0

¿Fuiste al sitio web pexpect? La Sección 8 muestra varios ejemplos de cómo se usa. –

0

que tenían el mismo problema para un lenguaje de programación que estoy trabajando, y terminó haciendo esto: https://github.com/perimosocordiae/plumbum/blob/master/lib/stdlib.py#L21

Por desgracia, se trata de la lectura de la salida de flujo de un carácter a la vez, la acumulación de la línea hasta que una se encuentra newline. Sin embargo, funciona y no conozco otra forma de obtener el mismo comportamiento.

+0

Por favor, compruebe el enlace pexpect que agregué a mi respuesta. –

+0

Parece que pexpect aún no es compatible con py3k. – perimosocordiae

2

Puede interactuar con el proceso mediante sondeo para que pueda tratar de interactuar con línea por línea:

Por ejemplo:

process = subprocess.Popen(["ls", "-lart"], 
       bufsize=-1, # fully buffered (default) 
       stdin=subprocess.PIPE, 
       stdout=subprocess.PIPE, 
       stderr=subprocess.PIPE, 
       cwd=os.curdir, 
       env=os.environ) 
my_stdout_file = open("stdout.txt", "w") 
while True: 
    process.poll() 
    line = process.stdout.readline() 
    my_stdout_file.write(line) 
    eline = process.stderr.readline() 
    if line: 
     stdout_lines.append(line) 
    if eline: 
     stderr_lines.append(eline) 
    if (line == "" and eline == "" and 
     process.returncode != None): 
     break 
1

pensé en compartir una solución que no hace use .poll(), .wait() o .communicate(). Un par de puntos:

  • utilizo import codecs porque mi salida incluye Asia del Este texto UTF-8
  • I trampa de cada línea con try: para filtrar dañado/inválido texto UTF-8
  • utilizo '\x0a' a forzar nueva línea de Linux independientemente de la plataforma.
  • Uso for line in iter(subproc.stderr.readline, ''): si necesita capturar stderr
  • Este enfoque genera una salida sólo cuando el programa infantil crea una salida
  • el uso del diccionario kw es demasiado para este ejemplo, sino que muestra cómo utilizar kwargs ** con subproceso

Código:

import subprocess 
import codecs 
import os 

kw = { 
    'bufsize': 0, 
    'executable': None, 
    'stdin': subprocess.PIPE, 
    'stdout': subprocess.PIPE, 
    'stderr': subprocess.PIPE, 
    'preexec_fn': None, 
    'close_fds': False, 
    'shell': False, 
    'cwd': None, 
    'env': None, 
    'universal_newlines': False, 
    'startupinfo': None, 
    'creationflags': 0, 
    } 

args = ['ls', '-lart'] 
kw['cwd'] = os.path.expanduser('~') 
logfile = os.path.expanduser('~/stdout.txt') 
stdlog = [] 

try: 
    subproc = subprocess.Popen(args,**kw) 
except: 
    print 'Error loading subprocess. Check arguments and kwargs' 
    exit() 

log = codecs.open(logfile,'w','utf-8') 
log.write(': Starting log for: \"%s\"\x0a'%(' '.join(args))) 
for line in iter(subproc.stdout.readline, ''): 
    try: 
     stdlog.append(line.rstrip().decode('utf-8')) 
     log.write(stdout[-1]+'\x0a') 
     print stdout[-1] 
    except: 
     pass 

log.flush() 
log.close() 
Cuestiones relacionadas