2010-01-29 6 views
19

Je voudrais exécuter plusieurs commandes dans une application autonome lancée à partir d'un script python, en utilisant des tubes. La seule façon de transmettre de manière fiable les commandes au fichier stdin du programme était d'utiliser Popen.communicate mais il ferme le programme après l'exécution de la commande. Si j'utilise Popen.stdin.write que la commande ne s'exécute que 1 fois sur 5 ou plus, cela ne fonctionne pas. Qu'est-ce que je fais mal?Exécution de plusieurs commandes à l'aide de Popen.stdin

Pour élaborer un peu:

J'ai une application qui écoute stdin pour les commandes et les exécute ligne par ligne. J'aimerais pouvoir exécuter l'application et lui transmettre diverses commandes, en fonction de l'interaction de l'utilisateur avec une interface graphique. Ceci est un exemple de test simple:

import os, string 
from subprocess import Popen, PIPE 

command = "anApplication" 
process = Popen(command, shell=False, stderr=None, stdin=PIPE) 

process.stdin.write("doSomething1\n") 
process.stdin.flush() 
process.stdin.write("doSomething2\n") 
process.stdin.flush() 

J'attends de voir le résultat des deux commandes mais je ne reçois pas de réponse. (Si j'exécute une des lignes Popen.write plusieurs fois de temps en temps, il fonctionne.)

Et si j'Execute:

process.communicate("doSomething1") 

il fonctionne parfaitement, mais l'application se termine.

+5

Veuillez inclure un extrait de code. Que voulez-vous dire par "commandes multiples"? –

+2

Votre question n'est pas claire du tout. Que sont les 'commandes multiples'? A quel stdin essaies-tu de passer des "commandes"? Comme Adam l'a mentionné, veuillez inclure un extrait de code. –

+0

Désolé les gars, j'ai apporté quelques modifications à la publication pour clarifier ce que j'aimerais faire. –

Répondre

-1

Il semble que votre application traite l'entrée d'un tuyau d'une manière étrange. Cela signifie qu'il n'obtiendra pas toutes les commandes que vous envoyez avant de fermer le tube.

donc l'approche que je suggère est juste pour le faire:

process.stdin.write("command1\n") 
process.stdin.write("command2\n") 
process.stdin.write("command3\n") 
process.stdin.close() 

Il ne ressemble pas à votre programme Python est lire la sortie de l'application, donc il ne devrait pas d'importance si vous envoyez les commandes tout à la fois comme ça.

+0

Le problème avec cette solution, c'est qu'elle exécute toutes les trois commandes à la fois, et non une par un, basé sur l'interaction des utilisateurs avec une interface graphique. Popen.communicate exécute simplement les commandes, mais je voudrais pouvoir les exécuter séparément. –

+0

@sz, je suppose que c'est le problème de l'application. Et je soupçonne que pour le réparer, il faudrait se donner la peine d'ouvrir un pseudo-terminal, qui est un type de périphérique virtuel sous Unix/Linux. Cela permet à un programme de prétendre être un terminal pour un autre programme. Si vous êtes sous Unix/Linux, vous pouvez tester pour vous assurer que c'est le problème de l'application et que Python ne doit pas avoir l'application '' cat -u'' et voir si les lignes sortent quand Python les écrit. – Omnifarious

0

Votre code dans la question devrait fonctionner comme il se doit. Si ce n'est pas le cas, votre code actuel est différent (par exemple, vous pouvez utiliser stdout=PIPE that may change the child buffering behavior) ou il peut indiquer un bogue dans l'application enfant elle-même tel que the read-ahead bug in Python 2 ie votre entrée est envoyée correctement par le processus parent mais elle est bloquée dans le tampon d'entrée interne de l'enfant.

Les travaux suivants sur ma machine Ubuntu:

#!/usr/bin/env python 
import time 
from subprocess import Popen, PIPE 

LINE_BUFFERED = 1 

#NOTE: the first argument is a list 
p = Popen(['cat'], bufsize=LINE_BUFFERED, stdin=PIPE, 
      universal_newlines=True) 
with p.stdin: 
    for cmd in ["doSomething1\n", "doSomethingElse\n"]: 
     time.sleep(1) # a delay to see that the commands appear one by one 
     p.stdin.write(cmd) 
     p.stdin.flush() # use explicit flush() to workaround 
         # buffering bugs on some Python versions 
rc = p.wait() 
1

Si je comprends bien votre problème, vous souhaitez interagir (par exemple envoyer des commandes et lire les réponses) avec une application console.

Si oui, vous pouvez consulter un comme pexpect pour Python, bibliothèque Attendez-vous comme: http://pexpect.sourceforge.net

Il vous rendra la vie plus facile, car il prendra soin de la synchronisation, le problème ddaa décrit également. Voir aussi: http://www.noah.org/wiki/Pexpect#Q:_Why_not_just_use_a_pipe_.28popen.28.29.29.3F

0

Le véritable problème ici est de savoir si l'application met en mémoire tampon sa sortie et si elle peut faire quoi que ce soit pour l'arrêter. Vraisemblablement, lorsque l'utilisateur génère une commande et clique sur un bouton de votre interface graphique, vous voulez voir la sortie de cette commande avant de demander à l'utilisateur d'entrer le suivant.

Malheureusement, vous ne pouvez rien faire du côté client de subprocess.Popen pour vous assurer que lorsque vous avez passé une commande à l'application, l'application s'assure que toutes les sorties sont vidées vers la destination finale.Vous pouvez appeler flush() tout ce que vous aimez, mais si cela ne fait pas la même chose, et vous ne pouvez pas le faire, alors vous êtes condamné à la recherche de solutions de contournement.

+0

Le sous-processus 'stdout' n'est * pas * redirigé dans ce cas. Par conséquent, la mise en mémoire tampon est la même que si l'application est exécutée à partir de la ligne de commande (ligne-buffered s'il s'agit d'un programme basé sur stdio). [La mise en mémoire tampon de 'stdin' du côté parent pourrait être contrôlée en utilisant' bufsize' (sur Python 2) ou explicite 'process.stdin.flush()'] (http://stackoverflow.com/a/7537987/4279). À moins qu'il y ait un bug (comme le bogue de lecture anticipée dans Python 2 qui pourrait être résolu en utilisant un appel explicite '.readline()'); le processus fils devrait pouvoir recevoir la commande immédiatement. – jfs

Questions connexes