J'essaie d'écrire un script wrapper pour un programme de ligne de commande (svnadmin verify) qui affichera un bel indicateur de progression pour l'opération. Cela me oblige à être en mesure de voir chaque ligne de sortie du programme encapsulé dès sa sortie.
J'ai pensé que j'exécuterais simplement le programme en utilisant subprocess.Popen
, utiliserais stdout=PIPE
, puis lisais chaque ligne au fur et à mesure et agirais en conséquence. Cependant, lorsque j'ai exécuté le code suivant, la sortie semblait être mise en mémoire tampon quelque part, ce qui l'a amenée à apparaître en deux morceaux, les lignes 1 à 332, puis 333 à 439 (la dernière ligne de sortie)
from subprocess import Popen, PIPE, STDOUT
p = Popen('svnadmin verify /var/svn/repos/config', stdout = PIPE,
stderr = STDOUT, shell = True)
for line in p.stdout:
print line.replace('\n', '')
Après avoir regardé un peu la documentation sur le sous-processus, j'ai découvert le bufsize
paramètre à Popen
, donc j'ai essayé de définir bufsize sur 1 (tampon chaque ligne) et 0 (pas de tampon), mais aucune des valeurs ne semblait changer la façon dont les lignes étaient livrées.
À ce stade, je commençais à comprendre les pailles, j'ai donc écrit la boucle de sortie suivante:
while True:
try:
print p.stdout.next().replace('\n', '')
except StopIteration:
break
mais a obtenu le même résultat.
Est-il possible d'obtenir la sortie de programme «en temps réel» d'un programme exécuté à l'aide d'un sous-processus? Existe-t-il une autre option en Python qui est compatible avec l'avant (non exec*
)?
la source
sydout=PIPE
pour que le sous-processus écrit directement sur votre console, en contournant le processus parent?Réponses:
J'ai essayé ceci, et pour une raison quelconque pendant que le code
tamponne agressivement, la variante
ne fait pas. Apparemment, il s'agit d'un bogue connu: http://bugs.python.org/issue3907 (Le problème est désormais "clos" depuis le 29 août 2018)
la source
while p.poll() is None
place dewhile True
et de supprimer leif not line
print(line.decode('utf-8').rstrip())
.PYTHONUNBUFFERED=1
. Ceci est particulièrement utile pour les sorties qui sont infiniesla source
p.stdout.close()
n'est pas clair.Vous pouvez diriger la sortie du sous-processus vers les flux directement. Exemple simplifié:
la source
.communicate()
? Ou le contenu est-il perdu dans les flux stderr / stdout parents?communicate()
méthode sur le retourCompletedProcess
. De plus,capture_output
est mutuellement exclusif avecstdout
etstderr
.Vous pouvez essayer ceci:
Si vous utilisez readline au lieu de read, il y aura des cas où le message d'entrée ne sera pas imprimé. Essayez-le avec une commande qui nécessite une entrée en ligne et voyez par vous-même.
la source
Le sous-processus Streaming stdin and stdout with asyncio in Python blog post par Kevin McCarthy montre comment le faire avec asyncio:
la source
import nest_asyncio; nest_asyncio.apply()
et utiliser la commande shell, c'est-à-direprocess = await create_subprocess_shell(*command, stdout=PIPE, stderr=PIPE, shell=True)
au lieu deprocess = await create_subprocess_exec(...)
. À votre santé!Problème de sortie en temps réel résolu: j'ai rencontré un problème similaire en Python, lors de la capture de la sortie en temps réel du programme c. J'ai ajouté " fflush (stdout) ;" dans mon code C. Cela a fonctionné pour moi. Voici le snip le code
<< Programme C >>
<< Programme Python >>
<< SORTIE >> Impression: Comptage 1 Impression: Comptage 2 Impression: Nombre 3
J'espère que ça aide.
~ sairam
la source
flush(stdout)
) en C ++. Merci!J'ai rencontré le même problème il y a quelque temps. Ma solution était d'abandonner l'itération de la
read
méthode, qui reviendra immédiatement même si votre sous-processus n'est pas terminé, etc.la source
Selon le cas d'utilisation, vous pouvez également désactiver la mise en mémoire tampon dans le sous-processus lui-même.
Si le sous-processus sera un processus Python, vous pouvez le faire avant l'appel:
Ou transmettez-le dans l'
env
argument àPopen
.Sinon, si vous êtes sous Linux / Unix, vous pouvez utiliser l'
stdbuf
outil. Par exemple, comme:Voir aussi ici à propos de
stdbuf
ou d'autres options.(Voir aussi ici pour la même réponse.)
la source
J'ai utilisé cette solution pour obtenir une sortie en temps réel sur un sous-processus. Cette boucle s'arrêtera dès que le processus sera terminé, laissant de côté le besoin d'une instruction break ou d'une possible boucle infinie.
la source
if out=='': break
aprèsout = sub_process...
Trouvé cette fonction "plug-and-play" ici . A travaillé comme un charme!
la source
stderr=subprocess.STDOUT
aide en fait beaucoup à capturer des données en streaming. Je suis en train de voter.Vous pouvez utiliser un itérateur sur chaque octet dans la sortie du sous-processus. Cela permet la mise à jour en ligne (les lignes se terminant par '\ r' écrasent la ligne de sortie précédente) à partir du sous-processus:
la source
Dans Python 3.x, le processus peut se bloquer car la sortie est un tableau d'octets au lieu d'une chaîne. Assurez-vous de le décoder en une chaîne.
À partir de Python 3.6, vous pouvez le faire en utilisant le paramètre
encoding
de Popen Constructor . L'exemple complet:Notez que ce code redirige
stderr
versstdout
et gère les erreurs de sortie .la source
L'utilisation de pexpect [ http://www.noah.org/wiki/Pexpect ] avec des readlines non bloquantes résoudra ce problème. Cela vient du fait que les tubes sont mis en mémoire tampon et que la sortie de votre application est donc mise en mémoire tampon par le tube.Par conséquent, vous ne pouvez pas accéder à cette sortie tant que le tampon ne se remplit pas ou que le processus n'est pas mort.
la source
Solution complète:
la source
universal_newlines=True
sur l'Popen()
appel, vous n'avez probablement pas besoin de les gérer vous-même, c'est tout l'intérêt de l'option.C'est le squelette de base que j'utilise toujours pour cela. Il facilite la mise en œuvre des délais d'expiration et est capable de gérer les processus de blocage inévitables.
la source
(Cette solution a été testée avec Python 2.7.15)
Il vous suffit de sys.stdout.flush () après chaque ligne lecture / écriture:
la source
Peu de réponses suggérant python 3.x ou pthon 2.x, le code ci-dessous fonctionnera pour les deux.
la source