No se pueden iniciar dos shells interactivos usando popen

Tengo el siguiente fragmento de código de Python y no puedo explicar por qué se comporta como lo hace.

import subprocess bash1 = subprocess.Popen(["/bin/bash","-l", "-i"], stdin=subprocess.PIPE) print "Checkpoint 1" bash2 = subprocess.Popen(["/bin/bash","-l", "-i"], stdin=subprocess.PIPE) print "Checkpoint 2" bash1.communicate("echo 'works1'") bash2.communicate("echo 'works2'") print "OK" 

Cuando lo ejecuto, obtengo el siguiente resultado:

 [user@localhost ~]$ python test.py Checkpoint 1 Checkpoint 2 [1]+ Stopped python test.py [user@localhost ~]$ [user@localhost ~]$ echo 'works1' works1 [user@localhost ~]$ logout [user@localhost ~]$ fg python test.py [user@localhost ~]$ echo 'works2' works2 [user@localhost ~]$ logout OK [user@localhost ~]$ 
  1. ¿Por qué se detiene el proceso de Python en la segunda llamada de Popen? (detenido por tty input), y como evitarlo?
  2. ¿Por qué recibo el mensaje de cierre de sesión después de que termine echo ‘works1’ y cómo evitarlo?

Respuesta a la pregunta 1:

Esto se debe a que un shell bash interactivo se debe conectar a un terminal (el ‘terminal de control’) y adquirirlo para procesar interrupciones de control de trabajo (por ejemplo, Control-Z). La segunda invocación intenta adquirir el terminal pero no puede, por lo que se suspende temporalmente.

Respuesta a la pregunta 2:

communicate escribe su argumento en la tubería estándar del proceso hijo y luego lo cierra. Bash termina cuando su stdin se agota (es como entrar en Control-D en una sesión de terminal bash).

Si desea mantener el proceso hijo de bash en ejecución, escriba directamente en su stdin en lugar de usar communicate siguiente communicate :

 bash1.stdin.write("echo 'works1'\n") 

Por cierto, debe agregar la nueva línea si desea que el comando se ejecute.

Una solución:

Si desea ejecutar dos o más shells interactivos, debe configurar el stdin de cada shell para que sea un pseudo-terminal en lugar de un PIPE de subproceso.

De acuerdo con la sugerencia de isedev, abrí 2 pseudoterminales. Lo importante es que el proceso maestro (este script de Python) lee y escribe en el archivo PTY maestro, mientras que el subproceso secundario usa el archivo esclavo como stdin, stdout y stderr. La parte inferior del código es solo para probar cómo funciona todo.

 import subprocess import os import pty import select import time # according to> http://fleckenzwerg2000.blogspot.com/2011/10/running-and-controlling-gnu-screen-from.html (master1, slave1) = pty.openpty() bash1 = subprocess.Popen(["bash", "-l", "-i"], stdin=slave1, stdout=slave1, stderr=slave1) (master2, slave2) = pty.openpty() bash2 = subprocess.Popen(["bash", "-l", "-i"], stdin=slave2, stdout=slave2, stderr=slave2) data = "echo 'bla'\n" ## taken from> http://stackoverflow.com/questions/14564904/how-to-send-tab-key-to-python-subprocesss-stdin def write_all(masterPTY, data): """Successively write all of data into a file-descriptor.""" while data: chars_written = os.write(masterPTY, data) data = data[chars_written:] return data def read_all(masterPTY): r,w,x = select.select([masterPTY], [], [], 10) if r: data = os.read(masterPTY, 1024) return data write_all(master1, "echo 'bla1'\n") write_all(master2, "echo 'bla2'\n") time.sleep(1) print read_all(master1) write_all(master1, "echo 'bla1'\n") time.sleep(1) print read_all(master2) time.sleep(1) os.close(master1) os.close(slave1) os.close(master2) os.close(slave2) bash1.terminate() bash2.terminate() print "OK" 

Eso es. Espero que ayude a alguien!