2010-01-29 21 views
19

Me gustaría ejecutar varios comandos en una aplicación independiente lanzada desde un script de python, usando pipes. La única forma en que podía pasar los comandos de manera confiable a la rutina del programa era usar Popen.com, pero cierra el programa después de que se ejecuta el comando. Si uso Popen.stdin.write, entonces el comando ejecuta solo 1 vez de cada 5, no funciona de manera confiable. ¿Qué estoy haciendo mal?Ejecutando múltiples comandos usando Popen.stdin

Para elaborar un poco:

Tengo una aplicación que escucha a la entrada estándar para los comandos y los ejecuta línea por línea. Me gustaría poder ejecutar la aplicación y pasarle varios comandos, según la interacción de los usuarios con una GUI. Este es un simple ejemplo de prueba:

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() 

que cabe esperar para ver el resultado de ambos comandos, pero no consigo ninguna respuesta. (Si ejecuto una de las líneas Popen.write varias veces de vez en cuando funciona.)

Y si ejecuto:

process.communicate("doSomething1") 

funciona perfectamente, pero la aplicación termina.

+5

Incluya un fragmento de código. ¿Qué quieres decir con "comandos múltiples"? –

+2

Su pregunta no está nada clara. ¿Qué son 'comandos múltiples'? ¿A quién está tratando de pasar 'comandos' ?. Como mencionó Adam, incluye un fragmento de código. –

+0

Lo siento muchachos, he hecho algunos cambios en la publicación para dejar en claro lo que me gustaría hacer. –

Respuesta

-1

Parece que su aplicación está tratando la entrada de una tubería de una manera extraña. Esto significa que no recibirá todos los comandos que envíe hasta que cierre la tubería.

lo tanto, el enfoque que sugeriría es sólo para hacer esto:

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

No suena como su programa de Python es la lectura de salida de la aplicación, por lo que no debería importar si envía los comandos todo a la vez así.

+0

El problema con esta solución es que ejecuta los tres comandos a la vez, y no uno por uno, basado en la interacción de los usuarios con una GUI. Simplemente ejecutando los comandos funcionan bien con Popen.communicate, pero me gustaría poder ejecutarlos por separado. –

+0

@sz, sospecho que este es el problema de la aplicación. Y sospecho que para solucionarlo tendrías que tomarse la molestia de abrir un pseudo-terminal, que es un tipo de dispositivo virtual en Unix/Linux. Permite a un programa pretender ser una terminal para otro programa. Si estás en Unix/Linux, puedes probar para asegurarte de que sea el problema de la aplicación y que Python no tenga la aplicación '' cat -u "' y ver si las líneas salen cuando Python las escribe. – Omnifarious

0

Tu código en la pregunta debería funcionar como está. Si no lo hace, entonces su código actual es diferente (por ejemplo, puede usar stdout=PIPE that may change the child buffering behavior) o podría indicar un error en la aplicación hija en sí, como the read-ahead bug in Python 2, es decir, su entrada es enviada correctamente por el proceso principal pero está atrapada en el búfer de entrada interno del niño.

Los siguientes trabajos en mi máquina de 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 entiendo su problema correctamente, desea interactuar (es decir, enviar comandos y leer las respuestas) con una aplicación de consola.

Si es así, es posible que desee comprobar una biblioteca Expect-como, como pexpect para Python: http://pexpect.sourceforge.net

Se le hará la vida más fácil, ya que se hará cargo de la sincronización, el problema que también DDAA describe. Vea también: http://www.noah.org/wiki/Pexpect#Q:_Why_not_just_use_a_pipe_.28popen.28.29.29.3F

0

El verdadero problema aquí es si la aplicación está almacenando en búfer su salida, y si es algo que puede hacer para detenerlo. Presumiblemente, cuando el usuario genera un comando y hace clic en un botón en su GUI, desea ver el resultado de ese comando antes de requerir que el usuario ingrese el siguiente.

Lamentablemente, no hay nada que pueda hacer en el lado del cliente de subprocess.Popen para asegurarse de que cuando haya pasado un comando a la aplicación, la aplicación se asegurará de que toda la salida se descargue al destino final.Puede llamar al flush() todo lo que quiera, pero si no hace lo mismo y no puede hacerlo, está condenado a buscar soluciones.

+0

subprocess 'stdout is * no * redirigido en este caso. Por lo tanto, el almacenamiento en memoria intermedia es el mismo que si la aplicación se ejecuta desde la línea de comandos (línea-buffer si se trata de un programa basado en stdio). [El almacenamiento en búfer de 'stdin' en el lado principal se puede controlar usando' bufsize' (en Python 2) o explícita 'process.stdin.flush()'] (http://stackoverflow.com/a/7537987/4279). A menos que exista un error (como el error de lectura anticipada en Python 2 que podría resolverse mediante una llamada explícita '.readline()'); el proceso hijo debería poder recibir el comando inmediatamente. – jfs

Cuestiones relacionadas