J'écris un script python qui utilise subprocess.Popen pour exécuter deux programmes (à partir du code C compilé) qui produisent chacun stdout. Le script obtient cette sortie et l'enregistre dans un fichier. Parce que le la sortie est parfois suffisamment grande pour submerger le sous-processus.PIPE, provoquant le blocage du script, j'envoie la sortie standard directement dans le fichier journal. Je veux que mon script écrive quelque chose au début et à la fin du fichier, et entre les deux sous-processus. Popen appelle. Cependant, lorsque je regarde mon fichier journal, tout ce que j'ai écrit dans le fichier journal à partir du script est tout ensemble en haut du fichier, suivi de toutes les sorties standard. Comment puis-je entrelacer mon texte ajouté dans le fichier ?
def run(cmd, logfile):
p = subprocess.Popen(cmd, Shell=True, universal_newlines=True, stdout=logfile)
return p
def runTest(path, flags, name):
log = open(name, "w")
print >> log, "Calling executable A"
a_ret = run(path + "executable_a_name" + flags, log)
print >> log, "Calling executable B"
b_ret = run(path + "executable_b_name" + flags, log)
print >> log, "More stuff"
log.close()
Le fichier journal contient: Appel de l'exécutable A Appel de l'exécutable B Plus de choses [... stdout des deux exécutables ...]
Existe-t-il un moyen de vider la sortie standard de A dans le journal après avoir appelé Popen, par exemple? Une autre chose qui pourrait être pertinente: l'exécutable A commence puis dépend de B, et après que B imprime des trucs et se termine, A imprime ensuite plus de trucs et se termine.
J'utilise Python 2.4 sur RHE Linux.
Vous pouvez appeler .wait () sur chaque objet Popen afin d'être sûr qu'il est terminé, puis appeler log.flush (). Peut-être quelque chose comme ça:
def run(cmd, logfile):
p = subprocess.Popen(cmd, Shell=True, universal_newlines=True, stdout=logfile)
ret_code = p.wait()
logfile.flush()
return ret_code
Si vous devez interagir avec l'objet Popen dans votre fonction externe, vous pouvez déplacer l'appel .wait () à la place.
Si je comprends bien, le programme A
attend que B
fasse son travail et A
ne quitte qu'après la sortie de B
.
Si B
peut démarrer sans que A
ne s'exécute, vous pouvez démarrer les processus dans l'ordre inverse:
from os.path import join as pjoin
from subprocess import Popen
def run_async(cmd, logfile):
print >>log, "calling", cmd
p = Popen(cmd, stdout=logfile)
print >>log, "started", cmd
return p
def runTest(path, flags, name):
log = open(name, "w", 1) # line-buffered
print >>log, 'calling both processes'
pb = run_async([pjoin(path, "executable_b_name")] + flags.split(), log)
pa = run_async([pjoin(path, "executable_a_name")] + flags.split(), log)
print >>log, 'started both processes'
pb.wait()
print >>log, 'process B ended'
pa.wait()
print >>log, 'process A ended'
log.close()
Remarque: l'appel de log.flush()
dans les processus principaux n'a aucun effet sur les tampons de fichiers dans les processus enfants.
Si les processus enfants utilisent la mise en mémoire tampon des blocs pour stdout, vous pouvez essayer de les forcer à vider plus tôt en utilisant pexpect, pty ou stdbuf (cela suppose que les processus utilisent la mise en mémoire tampon de ligne s'ils sont exécutés de manière interactive ou qu'ils utilisent C bibliothèque stdio pour les E/S).
Vous devez attendre la fin du processus avant de continuer. J'ai également converti le code pour utiliser un gestionnaire de contexte, qui est plus propre.
def run(cmd, logfile):
p = subprocess.Popen(cmd, Shell=True, universal_newlines=True, stdout=logfile)
p.wait()
return p
def runTest(path, flags, name):
with open(name, "w") as log:
print >> log, "Calling executable A"
a_ret = run(path + "executable_a_name" + flags, log)
print >> log, "Calling executable B"
b_ret = run(path + "executable_b_name" + flags, log)
print >> log, "More stuff"
Je dis juste garder les choses très simples. Logique de base du pseudo-code:
write your start messages to logA
execute A with output to logA
write your in-between messages to logB
execute B with output to logB
write your final messages to logB
when A & B finish, write content of logB to the end of logA
delete logB