261 votes

lire le sous-processus stdout ligne par ligne

Mon script python utilise des sous-processus pour appeler un linux utilitaire qui est très bruyant. Je veux stocker la totalité de la production d'un fichier journal, mais seulement de montrer à l'utilisateur. Je pensais que le suivant, mais la sortie ne présentent que dans mon application jusqu'à ce que l'utilitaire a produit une quantité importante de la production.

#fake_utility.py, just generates lots of output over time
import time
i = 0
while True:
   print hex(i)*512
   i += 1
   time.sleep(0.5)

#filters output
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
for line in proc.stdout:
   #the real code does filtering here
   print "test:", line.rstrip()

Le comportement que je veux vraiment, c'est pour le filtre de script pour imprimer chaque ligne comme il est reçu à partir du sous-processus. Sorta comme ce qu' tee n'mais avec du code python.

Ce qui me manque? Est-ce même possible?


Mise à jour:

Si un sys.stdout.flush() est ajouté à fake_utility.py le code du comportement souhaité en python 3.1. Je suis à l'aide de python 2.6. On pourrait penser que l'utilisation d' proc.stdout.xreadlines() serait la même que py3k, mais il ne le fait pas.


Mise à jour 2:

Ici est le minimum de code de travail.

#fake_utility.py, just generates lots of output over time
import sys, time
for i in range(10):
   print i
   sys.stdout.flush()
   time.sleep(0.5)

#display out put line by line
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
#works in python 3.0+
#for line in proc.stdout:
for line in iter(proc.stdout.readline,''):
   print line.rstrip()

201voto

Romulo Ceccon Points 5402

Il a été un long temps depuis que j'ai travaillé avec Python, mais je pense que le problème est avec l'énoncé for line in proc.stdout, qui lit l'ensemble de l'entrée avant de parcourir. La solution est d'utiliser readline() à la place:

#filters output
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
while True:
  line = proc.stdout.readline()
  if line != '':
    #the real code does filtering here
    print "test:", line.rstrip()
  else:
    break

Bien sûr, vous avez encore à traiter avec le sous-processus de " mise en mémoire tampon.

Remarque: selon la documentation de la solution avec un itérateur doit être équivalent à l'utilisation de readline(), sauf pour la lecture de la mémoire tampon, mais (ou justement à cause de cela) le changement proposé n'a produire des résultats différents pour moi (Python 2.5 sur Windows XP).

22voto

Steve Carter Points 21

En effet, si vous triiez l'itérateur, la mise en mémoire tampon pourrait maintenant être votre problème. Vous pourriez dire au python dans le sous-processus de ne pas mettre en mémoire tampon sa sortie.

 proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
 

devient

 proc = subprocess.Popen(['python','-u', 'fake_utility.py'],stdout=subprocess.PIPE)
 

J'en avais besoin pour appeler python depuis Python.

1voto

rossipedia Points 10922

Ce que vous recherchez, c'est stdout sans tampon. Voir cette question

-2voto

user456849 Points 11

Tout ce que vous devez faire est d'exécuter un processus secondaire.call(): util.py:

#!/usr/bin/python2.6

importer des sous-processus

commande = ['./fake_util.py']

essayez:
 proc = sous-processus.appel(commande)
sauf OSError, err:
 print " a Obtenu exception commande en cours "%s": %s' % (commande, err)

fake_util.py:

#!/usr/bin/python2.6
#fake_utility.py, génère beaucoup de production au fil du temps
le délai d'importation
i = 0
while True:
 imprimer hex(i)*512
 i += 1
temps.sommeil(0.5)

En cours d'exécution ./util.py maintenant produit une sortie comme il est généré:

x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x1

./util.py
0x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x20x2
^CTraceback (most recent call last):
 Le fichier "./util.py", ligne 8, dans 
 proc = sous-processus.appel(commande)
 Le fichier "/usr/lib/python2.6/subprocess.py" de ligne, 480, en appel
 retour Popen(*popenargs, **kwargs).wait()
 Le fichier "/usr/lib/python2.6/subprocess.py", de la ligne de 1170, dans l'attente
Traceback (most recent call last):
 Le fichier "./fake_util.py", ligne 8, dans 
temps.sommeil(0.5)
KeyboardInterrupt
 pid, sts = _eintr_retry_call(os.waitpid, de soi.pid, 0)
 Le fichier "/usr/lib/python2.6/subprocess.py" de ligne, 465, dans _eintr_retry_call
 retour func(*args)
KeyboardInterrupt

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X