python subprocess stdout stdin pexpect

Múltiples entradas y salidas en subproceso de python se comunican



subprocess stdout (4)

Necesito hacer algo como esta publicación , pero necesito crear un subproceso que pueda recibir entrada y salida muchas veces. La respuesta aceptada de esa publicación tiene un buen código ...

from subprocess import Popen, PIPE, STDOUT p = Popen([''grep'', ''f''], stdout=PIPE, stdin=PIPE, stderr=STDOUT) grep_stdout = p.communicate(input=b''one/ntwo/nthree/nfour/nfive/nsix/n'')[0] print(grep_stdout.decode()) # four # five

... que me gustaría continuar así:

grep_stdout2 = p.communicate(input=b''spam/neggs/nfrench fries/nbacon/nspam/nspam/n'')[0] print(grep_stdout2.decode()) # french fries

Pero, por desgracia, me sale el siguiente error:

Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/subprocess.py", line 928, in communicate raise ValueError("Cannot send input after starting communication") ValueError: Cannot send input after starting communication

El método proc.stdin.write () no le permite recopilar resultados, si lo entiendo correctamente. ¿Cuál es la forma más sencilla de mantener abiertas las líneas para la entrada / salida en curso?

Editar: ====================

Parece que pexpect es una biblioteca útil para lo que estoy tratando de hacer, pero tengo problemas para que funcione. Aquí hay una explicación más completa de mi tarea real. Estoy usando hfst para obtener análisis gramaticales de palabras individuales (rusas). Lo siguiente demuestra su comportamiento en un shell bash:

$ hfst-lookup analyser-gt-desc.hfstol > слово слово слово+N+Neu+Inan+Sg+Acc 0.000000 слово слово+N+Neu+Inan+Sg+Nom 0.000000 > сработай сработай сработать+V+Perf+IV+Imp+Sg2 0.000000 сработай сработать+V+Perf+TV+Imp+Sg2 0.000000 >

Quiero que mi script pueda obtener los análisis de un formulario a la vez. Intenté un código como este, pero no funciona.

import pexpect analyzer = pexpect.spawnu(''hfst-lookup analyser-gt-desc.hfstol'') for newWord in [''слово'',''сработай''] : print(''Trying'', newWord, ''...'') analyzer.expect(''> '') analyzer.sendline( newWord ) print(analyzer.before) # trying слово ... # # trying сработай ... # слово # слово слово+N+Neu+Inan+Sg+Acc 0.000000 # слово слово+N+Neu+Inan+Sg+Nom 0.000000 # #

Obviamente, he entendido mal lo que pexpect.before hace antes. ¿Cómo puedo obtener la salida de cada palabra, una a la vez?


Esta respuesta debe atribuirse a @JFSebastian. ! Gracias por los comentarios!

El siguiente código obtuvo mi comportamiento esperado:

import pexpect analyzer = pexpect.spawnu(''hfst-lookup analyser-gt-desc.hfstol'') analyzer.expect(''> '') for word in [''слово'', ''сработай'']: print(''Trying'', word, ''...'') analyzer.sendline(word) analyzer.expect(''> '') print(analyzer.before)


HFST tiene enlaces de Python: https://pypi.python.org/pypi/hfst

Usarlos debería evitar todo el problema del vaciado, y le dará una API más limpia para trabajar que analizar el resultado de la cadena de pexpect.

Desde Python REPL, puede obtener algunos documentos sobre los enlaces con

dir(hfst) help(hfst.HfstTransducer)

o lea https://hfst.github.io/python/3.12.2/QuickStart.html

Arrebatando las partes relevantes de los documentos:

istr = hfst.HfstInputStream(''hfst-lookup analyser-gt-desc.hfstol'') transducers = [] while not (istr.is_eof()): transducers.append(istr.read()) istr.close() print("Read %i transducers in total." % len(transducers)) if len(transducers) == 1: out = transducers[0].lookup_optimize("слово") print("got %s" % (out,)) else: pass # or handle >1 fst in the file, though I''m guessing you don''t use that feature


Siempre que desee enviar información al proceso, use proc.stdin.write() . Siempre que desee obtener resultados del proceso, use proc.stdout.read() . Los argumentos stdin y stdout para el constructor deben establecerse en PIPE .


Popen.communicate() es un método auxiliar que realiza una escritura única de datos en stdin y crea hilos para extraer datos de stdout y stderr . Cierra stdin cuando termina de escribir datos y lee stdout y stderr hasta que se cierran esas tuberías. No puede communicate por segunda vez porque el niño ya ha salido cuando regresa.

Una sesión interactiva con un proceso secundario es bastante más complicada.

Un problema es si el proceso secundario incluso reconoce que debería ser interactivo. En las bibliotecas C que la mayoría de los programas de línea de comandos utilizan para la interacción, los programas que se ejecutan desde terminales (por ejemplo, una consola de Linux o un pseudo terminal "pty") son interactivos y eliminan su salida con frecuencia, pero los que se ejecutan desde otros programas a través de PIPES no son interactivo y vaciar su salida con poca frecuencia.

Otra es cómo debe leer y procesar stdout y stderr sin bloqueo. Por ejemplo, si bloquea la lectura stdout , pero stderr llena su tubo, el niño se detendrá y usted estará atascado. Puede usar subprocesos para colocar ambos en búferes internos.

Otra es cómo lidias con un niño que sale inesperadamente.

Para sistemas "unixy" como Linux y OSX, el módulo pexpect está escrito para manejar las complejidades de un proceso secundario interactivo. Para Windows, no hay una buena herramienta que conozca para hacerlo.