2009-09-07 6 views
34

Je veux la sortie de l'exécution Test_Pipe.py, j'ai essayé le code suivant sur Linux mais cela n'a pas fonctionné.Comment obtenir la sortie de subprocess.Popen()

Test_Pipe.py

import time 
while True : 
    print "Someting ..." 
    time.sleep(.1) 

Caller.py

import subprocess as subp 
import time 

proc = subp.Popen(["python", "Test_Pipe.py"], stdout=subp.PIPE, stdin=subp.PIPE) 

while True : 
    data = proc.stdout.readline() #block/wait 
    print data 
    time.sleep(.1) 

La ligne proc.stdout.readline() a été bloqué, donc pas de copies de données sur.

+0

Dupliquer: http://stackoverflow.com/search?q=%5Bpython%5D+subprocess+output, http://stackoverflow.com/questions/803265/getting-realtime-output-using-subprocess, http: //stackoverflow.com/questions/1277866/python-subprocess-module-looping-over-stdout-of-child-process –

Répondre

39

Vous pouvez évidemment utiliser subprocess.communicate mais je pense que vous recherchez une entrée et une sortie en temps réel. Readline a été bloqué car le processus attend probablement votre entrée. Vous pouvez lire le caractère par caractère pour surmonter ce comme ce qui suit:

import subprocess 
import sys 

process = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE 
) 

while True: 
    out = process.stdout.read(1) 
    if out == '' and process.poll() != None: 
     break 
    if out != '': 
     sys.stdout.write(out) 
     sys.stdout.flush() 
+2

[vous n'avez pas besoin de 'process.poll()' dans ce cas] (http: // stackoverflow.com/a/17701672/4279). – jfs

12

Pour éviter les nombreux problèmes qui peuvent toujours survenir avec mise en mémoire tampon pour des tâches telles que « obtenir au processus principal en temps réel de sortie du sous-processus », je recommande toujours d'utiliser pexpect pour toutes les plates-formes autres que Windows, wexpect sous Windows, au lieu de subprocess, lorsque ces tâches sont souhaitées.

+0

Lien mis à jour vers pexpect: https://github.com/pexpect/pexpect –

20

L'extrait de Nadia fonctionne, mais appeler avec un tampon de 1 octet est fortement déconseillé. La meilleure façon de le faire serait de définir le descripteur de fichier stdout à non bloquant avec fcntl

fcntl.fcntl(
    proc.stdout.fileno(), 
    fcntl.F_SETFL, 
    fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK, 
) 

puis utiliser select pour tester si les données sont prêtes

while proc.poll() == None: 
    readx = select.select([proc.stdout.fileno()], [], [])[0] 
    if readx: 
     chunk = proc.stdout.read() 
     print chunk 

Elle a eu raison de ce que votre problème doit être différent de ce que vous avez publié en tant que Caller.py et Test_Pipe.py fonctionnent comme prévu.

+0

Il ne produira pas la sortie plus tôt que le code de la question en raison de [le problème de blocage des blocs.Voir ma réponse] (http://stackoverflow.com/a/17701672/4279). – jfs

+0

Le code produit une sortie en temps réel. Avez-vous eu un problème avec cela? –

+0

suivez le lien dans le commentaire. – jfs

7

Test_Pipe.py tampons STDOUT par défaut afin proc en Caller.py ne voient pas de sortie jusqu'à ce que la mémoire tampon de l'enfant est plein (si la taille de la mémoire tampon est 8KB alors il faut environ une minute pour remplir Tampon stdout Test_Pipe.py).

Pour que la sortie ne soit pas tamponnée (mise en mémoire tampon pour les flux de texte), vous pouvez transmettre -u flag au script enfant Python. Il permet de lire la ligne de sortie de sous-processus par ligne en « temps réel »:

import sys 
from subprocess import Popen, PIPE 

proc = Popen([sys.executable, "-u", "Test_Pipe.py"], stdout=PIPE, bufsize=1) 
for line in iter(proc.stdout.readline, b''): 
    print line, 
proc.communicate() 

Voir les liens Python: read streaming input from subprocess.communicate() sur la façon de résoudre le problème bloc-tampon pour les processus enfants non-Python.

+1

Encore une fois, vous utilisez un tampon de 1 octet qui est incroyablement inefficace. –

+4

@DerrickPetzold: faux. 'bufsize = 1' signifie" ligne-buffered ". Il utilise la même taille de tampon que 'bufsize = -1'. Vous pourriez avoir découvert que vos deux commentaires sont faux si vous étiez en fait pour exécuter le code (comparer les performances de temps et mesurer le temps avant que le premier octet soit lu) – jfs

+1

j'aime cette façon de le faire parce que vous pouvez imprimer directement à l'écran et aussi stocker les résultats de la popen pour faire quelque chose avec, et plus tard sur vérifier le code d'erreur etc ... thumbs up =) je l'exécute sans le bufsize et fonctionne bien pour moi dans mon code. – pelos

Questions connexes