2013-05-15 19 views
5

Używam skryptu Pythona do uruchomienia procesu przy użyciu subprocess.Popen, a jednocześnie zapisuję dane wyjściowe w pliku tekstowym, a także wypisuję je na konsoli. To jest mój kod:Uzyskiwanie danych wyjściowych procesu w środowisku wykonawczym

result = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 
for line in result.stdout.readlines(): #read and store result in log file 
    openfile.write("%s\n" %line) 
    print("%s" %line) 

Powyższy kod działa dobrze, ale co to robi to pierwszy kończy proces i przechowuje dane wyjściowe w wyniku zmiennej. Po tym dla pętli przechowuje dane wyjściowe, a także je drukuje.

Ale chcę dane wyjściowe w czasie wykonywania (ponieważ mój proces może zająć wiele godzin, nie otrzymam żadnych wyników przez wszystkie te godziny).

Czy istnieje jakaś inna funkcja, która dynamicznie generuje dane wyjściowe (w czasie wykonywania), oznacza, że ​​gdy tylko proces wyświetli pierwszą linię, powinien zostać wydrukowany.

+1

Nigdy faktycznie próbowałem, ale myślę, że mają wysłać własną rękę Python 'plik' obiekt do argumentu' stdout' (lub 'stdin' lub' stderr'). Następnie musisz odpytać ten plik. "Podproces" został wymyślony, aby oszczędzić ci bólu, ale wygląda na to, że nie masz wyboru. Powodzenia. –

+1

_ "najpierw kończy proces i przechowuje wynik w wyniku" _ - to po prostu nieprawda. – Eric

+0

"najpierw kończy proces i przechowuje wynik w wyniku" - to po prostu nieprawda. Cóż, kiedy uruchomię polecenie Popen, działa dalej, aż proces się zakończy, a następnie wykonuje kolejne kodowanie. Jeśli działa to w jakiś inny sposób, bardzo chciałbym to wiedzieć. – Niyojan

Odpowiedz

5

Problem polega na tym, że .readlines() pobiera całe wyjście przed powrotem, ponieważ konstruuje pełną listę. Wystarczy iteracji bezpośrednio:

for line in result.stdout: 
    print line 
+1

uwaga: ['dla linii w wyniku.stdout' nie zwraca wierszy w "czasie rzeczywistym" na Pythonie 2, użyj 'dla linii w iter (result.stdout.readline, b '')' zamiast] (http://ideone.com/8KFawl) (twój 'print linijka sugeruje, że spodziewasz się, że będzie działać na Pythonie 2. [Na Pythonie 3 działa dobrze] (http://ideone.com/EUpeGV) – jfs

+0

Tak, działa, otrzymuję dane wyjściowe w czasie rzeczywistym, dziękuję. – Niyojan

1

Można iteracyjne nad liniami pojedynczo za pomocą readline na rurze:

while True: 
    line = result.stdout.readline() 
    print line.strip() 
    if not line: 
     break 

Linie zawierać spływu \n które uproszczoną do druku. Po zakończeniu procesu readline zwraca pusty ciąg, dzięki czemu wiadomo, kiedy należy zatrzymać.

+1

Przykro mi, ale nie dostałeś mojego pytania. Zasugerowałeś, że już to robię za pomocą pętli for, czego chcę, to line by line, podczas gdy proces jest nadal w stanie. – Niyojan

+1

czy próbowałeś? Używasz 'readlines', który zwraca wszystkie wiersze. Jest to możliwe tylko po zakończeniu. Z 'readline' dostajesz tylko następny –

+0

result.stdout działa dobrze dla mnie, ale twoje funkcje line.strip() są pomocne, ponieważ otrzymywałem zbyt wiele" b "\ r \ n" "przed nim, dziękuję – Niyojan

3

.readlines() zwraca listę wszystkie linie proces wróci natomiast otwarte, to znaczy, że nic nie jest aż otrzymał wszystkie wyjście z podproces powrotu. Aby przeczytać wiersz po wierszu w „czasie rzeczywistym”:

import sys 
from subprocess import Popen, PIPE 

proc = Popen(cmd, shell=True, bufsize=1, stdout=PIPE) 
for line in proc.stdout: 
    openfile.write(line) 
    sys.stdout.buffer.write(line) 
    sys.stdout.buffer.flush() 
proc.stdout.close() 
proc.wait() 

Uwaga: jeśli podproces używa bloku buforowanie, gdy jest uruchomiony w trybie nieinteraktywnym; możesz potrzebować pexpect, pty modules lub stdbuf, unbuffer, script commands.

Uwaga: na Pythonie 2, można również użyć iter(), aby „w czasie rzeczywistym” Wyjście:

for line in iter(proc.stdout.readline, ""): 
    openfile.write(line) 
    print line, 
Powiązane problemy