2013-07-01 11 views
17

Questo è un seguito fino a this question, ma se voglio passare un argomento a stdin a subprocess, come posso ottenere l'output in tempo reale? Questo è ciò che attualmente ho; Ho anche provato a sostituire Popen con call dal modulo subprocess e questo porta solo alla sospensione dello script.stampa stdout in tempo reale da un sottoprocesso che richiede stdin

from subprocess import Popen, PIPE, STDOUT 
cmd = 'rsync --rsh=ssh -rv --files-from=- thisdir/ servername:folder/' 
p = Popen(cmd.split(), stdout=PIPE, stdin=PIPE, stderr=STDOUT) 
subfolders = '\n'.join(['subfolder1','subfolder2']) 
output = p.communicate(input=subfolders)[0] 
print output 

Nella prima domanda cui non ho dovuto passare stdin mi è stato suggerito di usare p.stdout.readline, non non c'è spazio lì per qualcosa di tubo stdin.

Addendum: Questo funziona per il trasferimento, ma vedo l'output solo alla fine e mi piacerebbe vedere i dettagli del trasferimento mentre sta accadendo.

+0

se invece si è interessati a vedere l'uscita poi basta rilascia 'stdout = PIPE'. – jfs

risposta

25

Al fine di afferrare stdout dal sottoprocesso in tempo reale, è necessario decidere esattamente quale comportamento che si desidera; in particolare, è necessario decidere se si desidera gestire l'output riga per riga o carattere per carattere e se si desidera bloccare mentre si attende l'output o essere in grado di fare qualcos'altro durante l'attesa.

Sembra che probabilmente saranno sufficienti per il vostro caso a leggere l'output in modo line-buffered, il blocco fino a quando ogni linea completa in arrivo, il che significa che le funzioni comfort offerti da subprocess sono abbastanza buone:

p = subprocess.Popen(some_cmd, stdout=subprocess.PIPE) 
# Grab stdout line by line as it becomes available. This will loop until 
# p terminates. 
while p.poll() is None: 
    l = p.stdout.readline() # This blocks until it receives a newline. 
    print l 
# When the subprocess terminates there might be unconsumed output 
# that still needs to be processed. 
print p.stdout.read() 

Se avete bisogno di scrivere al stdin del processo, basta usare un altro tubo:

p = subprocess.Popen(some_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 
# Send input to p. 
p.stdin.write("some input\n") 
p.stdin.flush() 
# Now start grabbing output. 
while p.poll() is None: 
    l = p.stdout.readline() 
    print l 
print p.stdout.read() 

Pace l'altra risposta, non c'è alcuna necessità di indiretta tramite un file in per passare l'input al sottoprocesso.

+0

non so che non potrei ottenere 'sys.stdin.read()' per restituire qualcosa nel file chiamato con python2. 6 con questo metodo ... ecco perché non l'ho messo come risposta ...ma forse ho rotto qualcosa. –

+1

Quando chiamato senza argomento 'read()' non ritorna finché non incontra 'EOF' (sta cercando di leggere l'interezza dell'oggetto file su cui è chiamato, e non sa che ha consumato tutto il file fino a raggiunge "EOF"). Questo è raramente il comportamento che si vuole quando si legge l'input. Si dovrebbe passare un numero specificato di byte come argomento a 'read()' (nel qual caso la chiamata 'read()' ritornerà dopo aver incontrato quel numero di byte o 'EOF', a seconda di quale viene prima) o usare' readline () '(che tornerà dopo aver incontrato una nuova riga). – Alp

+0

ok il tuo diritto +1 grazie per aver risolto il problema con –

2

qualcosa come questo penso

from subprocess import Popen, PIPE, STDOUT 

p = Popen('c:/python26/python printingTest.py', stdout = PIPE, 
     stderr = PIPE) 
for line in iter(p.stdout.readline, ''): 
    print line 
p.stdout.close() 

utilizzando un iteratore restituirà risultati in tempo reale fondamentalmente ..

al fine di inviare input per stdin si avrebbe bisogno di qualcosa come

other_input = "some extra input stuff" 
with open("to_input.txt","w") as f: 
    f.write(other_input) 
p = Popen('c:/python26/python printingTest.py < some_input_redirection_thing', 
     stdin = open("to_input.txt"), 
     stdout = PIPE, 
     stderr = PIPE) 

questo sarebbe simile al comando della shell linux di

%prompt%> some_file.o < cat to_input.txt 

vedere alpi risposta per meglio passare a stdin

+0

Grazie, questa era una risposta data nella mia domanda precedente in cui non avevo bisogno di 'stdin', ma non so come passare ad esso l'argomento 'input' come farei per' p.communicate' – hatmatrix

+0

vedere le modifiche. .. avresti bisogno di mettere la stringa di input in un file e passare un filehandler aperto all'argomento stdin del costruttore –

1

Se si passa tutti i vostri input prima di iniziare a leggere l'output e se per "real-time" Vuoi dire che ogni volta che il sottoprocesso svuota il suo buffer stdout:

from subprocess import Popen, PIPE, STDOUT 

cmd = 'rsync --rsh=ssh -rv --files-from=- thisdir/ servername:folder/' 
p = Popen(cmd.split(), stdout=PIPE, stdin=PIPE, stderr=STDOUT, bufsize=1) 
subfolders = '\n'.join(['subfolder1','subfolder2']) 
p.stdin.write(subfolders) 
p.stdin.close() # eof 
for line in iter(p.stdout.readline, ''): 
    print line, # do something with the output here 
p.stdout.close() 
rc = p.wait() 
Problemi correlati