2011-03-02 16 views
8

Mój skrypt python używa podprocesu do wywoływania innego skryptu, który generuje wynik bardzo powolny (linia po linii). Chciałbym zapisać wyjściową linię po linii do pliku, nie wtedy, gdy cały proces się kończy i zapisuje całe wyjście jako ciąg. Poniższy kod zapisuje wynik do "pliku", gdy kończy się "skrypt".Zapisywanie stdout z podprocesu.Popen do pliku wiersz po linii

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

Czy to możliwe? Thanx, Chris

Odpowiedz

1

Tak, jest to możliwe. Oto funkcja, którą napisałem dla uprzęży testowej, aby przeprowadzić testowanie jednostkowe skryptów powłoki 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) 

Funkcja zwraca krotki zawierający zagadnienia kod zwrotny powłoki przez sys.exit(), standardowy tekst wyjściowy, a standardowy tekst wyjściowy błędu. Oba są ciągami tekstowymi, więc musisz użyć splitlines, aby podzielić je na wiersze przed przetworzeniem.

Jeśli naprawdę potrzebujesz interakcji z wyjściem, linia po linii, prawdopodobnie lepiej jest użyć pexpect niż modułu subprocess.

+0

Czy możesz podać przykład stosując pexpect? – perimosocordiae

+0

Czy poszedłeś na stronę Pexpect? Rozdział 8 pokazuje kilka przykładów tego, jak jest używany. –

0

miałem ten sam problem na język programowania ja pracuję, a zakończył się w ten sposób: https://github.com/perimosocordiae/plumbum/blob/master/lib/stdlib.py#L21

Niestety, wiąże się to czyta z wyjścia strumienia znak naraz, gromadząc linię aż do chwili znaleziono nowy wiersz. Działa to jednak i nie znam żadnego innego sposobu na uzyskanie tego samego zachowania.

+0

Proszę sprawdzić link pexpect, który dodałem do mojej odpowiedzi. –

+0

Wygląda na to, że pexpect nie jest jeszcze kompatybilny z py3k. – perimosocordiae

2

można wchodzić w interakcje z procesem stosując sondę tak, że można próbować wchodzić w interakcje z nim wiersz po wierszu:

Na przykład:

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

myślałem, że dzielić się rozwiązanie, które nie użyj .poll(), .wait() lub .communicate(). Kilka punktów:

  • używam import codecs bo moje wyjście zawiera wschodnioazjatyckich UTF-8 Tekst
  • I pułapkę każda linia z try: odfiltrować uszkodzone/nieprawidłowy UTF-8 tekstową
  • używam '\x0a' do wymuszać newline Linuxa niezależnie od platformy.
  • Zastosowanie for line in iter(subproc.stderr.readline, ''): jeśli trzeba przechwycić stderr
  • Takie podejście generuje moc tylko wtedy, gdy dziecko Program tworzy wyświetlamy
  • Korzystanie słownika kw jest przesadą dla tego przykładu, ale pokazuje, jak używać ** kwargs z podproces

Kod:

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() 
Powiązane problemy