python subprocess stdout stdin interactive

Ejecutando un comando interactivo desde Python



subprocess stdout (2)

Tengo un script que quiero ejecutar desde Python (2.6.5) que sigue la lógica siguiente:

  • Preguntar al usuario por la contraseña. Parece que ("Ingresar contraseña:") (* Nota: la entrada no se muestra en la pantalla)
  • Salida información irrelevante
  • Preguntar al usuario la respuesta ("Blah Blah filename.txt blah blah (S / N) ?:")

La última línea de solicitud contiene texto que necesito analizar (nombre de archivo.txt). La respuesta proporcionada no importa (el programa podría salir de aquí sin proporcionar uno, siempre que pueda analizar la línea)

Mis requisitos son algo similares a envolver una aplicación de línea de comandos interactiva en un script de Python , pero las respuestas parecen un poco confusas, y las mías aún se cuelgan incluso cuando el OP menciona que no lo hace por él.

Al mirar alrededor, he llegado a la conclusión de que el subprocess es la mejor manera de hacer esto, pero tengo algunos problemas. Aquí está mi línea de Popen:

p = subprocess.Popen("cmd", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE)

  • Cuando llamo a read() o readline() en la stdout , el indicador es impresora en la pantalla y se cuelga.

  • Si llamo a write("password/n") para stdin , el aviso se escribe en la pantalla y se cuelga. El texto en write() no está escrito (no muevo el cursor una nueva línea).

  • Si llamo p.communicate("password/n") , el mismo comportamiento que escribe ()

Estaba buscando algunas ideas aquí sobre la mejor manera de ingresar a stdin y posiblemente cómo analizar la última línea de la salida si te sientes generoso, aunque probablemente podría resolverlo al final.


El uso de subprocesos puede ser un poco excesivo para tareas simples. En su lugar, se puede utilizar os.spawnvpe. Generará shell shell como un proceso. Podrás comunicarte interactivamente con el script. En este ejemplo pasé la contraseña como argumento, obviamente no es una buena idea.

import os import sys from getpass import unix_getpass def cmd(cmd): cmd = cmd.split() code = os.spawnvpe(os.P_WAIT, cmd[0], cmd, os.environ) if code == 127: sys.stderr.write(''{0}: command not found/n''.format(cmd[0])) return code password = unix_getpass(''Password: '') cmd_run = ''./run.sh --password {0}''.format(password) cmd(cmd_run) pattern = raw_input(''Pattern: '') lines = [] with open(''filename.txt'', ''r'') as fd: for line in fd: if pattern in line: lines.append(line) # manipulate lines


Si se está comunicando con un programa que genera subprocesos, debería revisar la lectura de no bloqueo en un subproceso . PIPE en python . Tuve un problema similar con mi aplicación y descubrí que el uso de Colas es la mejor manera de hacer una comunicación continua con un subproceso.

En cuanto a obtener valores del usuario, siempre puede usar la función raw_input () incorporada para obtener respuestas, y para las contraseñas, intente usar el módulo getpass para obtener contraseñas sin eco de su usuario. Luego puede analizar esas respuestas y escribirlas en la entrada estándar de su subproceso.

Terminé haciendo algo parecido a lo siguiente:

import sys import subprocess from threading import Thread try: from Queue import Queue, Empty except ImportError: from queue import Queue, Empty # python 3.x def enqueue_output(out, queue): for line in iter(out.readline, b''''): queue.put(line) out.close() def getOutput(outQueue): outStr = '''' try: while True: #Adds output from the Queue until it is empty outStr+=outQueue.get_nowait() except Empty: return outStr p = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, universal_newlines=True) outQueue = Queue() errQueue = Queue() outThread = Thread(target=enqueue_output, args=(p.stdout, outQueue)) errThread = Thread(target=enqueue_output, args=(p.stderr, errQueue)) outThread.daemon = True errThread.daemon = True outThread.start() errThread.start() try: someInput = raw_input("Input: ") except NameError: someInput = input("Input: ") p.stdin.write(someInput) errors = getOutput(errQueue) output = getOutput(outQueue)

Una vez que haya realizado las colas y los subprocesos iniciados, puede realizar un ciclo para obtener información del usuario, obtener errores y resultados del proceso, y procesarlos y mostrarlos al usuario.