tutorial powered payton online language interprete idle developing python linux bash python-2.x tty

payton - python powered



Ejecute Bash interactivo con Popen y un TTY TTY dedicado (3)

tendrá que pasar la entrada para leer y luego imprimir x.

Necesito ejecutar una instancia interactiva de Bash en un proceso separado en Python con su propio TTY dedicado (no puedo usar pexpect). Utilicé este fragmento de código que comúnmente veo utilizado en programas similares:

master, slave = pty.openpty() p = subprocess.Popen(["/bin/bash", "-i"], stdin=slave, stdout=slave, stderr=slave) os.close(slave) x = os.read(master, 1026) print x subprocess.Popen.kill(p) os.close(master)

Pero cuando lo ejecuto obtengo el siguiente resultado:

$ ./pty_try.py bash: cannot set terminal process group (10790): Inappropriate ioctl for device bash: no job control in this shell

Strace of the run muestra algunos errores:

... readlink("/usr/bin/python2.7", 0x7ffc8db02510, 4096) = -1 EINVAL (Invalid argument) ... ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffc8db03590) = -1 ENOTTY (Inappropriate ioctl for device) ... readlink("./pty_try.py", 0x7ffc8db00610, 4096) = -1 EINVAL (Invalid argument)

El fragmento de código parece bastante sencillo, ¿Bash no está recibiendo algo que necesita? ¿Cual podría ser el problema aquí?


Esta es la solución que funcionó para mí al final (como lo sugirió qarma):

libc = ctypes.CDLL(''libc.so.6'') master, slave = pty.openpty() p = subprocess.Popen(["/bin/bash", "-i"], preexec_fn=libc.setsid, stdin=slave, stdout=slave, stderr=slave) os.close(slave) ... do stuff here ... x = os.read(master, 1026) print x


Esta es una solución para ejecutar un comando interactivo en subproceso. Utiliza pseudo-terminal para hacer que stdout no bloquee (también un comando necesita un dispositivo tty, por ejemplo, bash). usa seleccionar para manejar la entrada y salida al subproceso.

#!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys import select import termios import tty import pty from subprocess import Popen command = ''bash'' # command = ''docker run -it --rm centos /bin/bash''.split() # save original tty setting then set it to raw mode old_tty = termios.tcgetattr(sys.stdin) tty.setraw(sys.stdin.fileno()) # open pseudo-terminal to interact with subprocess master_fd, slave_fd = pty.openpty() # use os.setsid() make it run in a new process group, or bash job control will not be enabled p = Popen(command, preexec_fn=os.setsid, stdin=slave_fd, stdout=slave_fd, stderr=slave_fd, universal_newlines=True) while p.poll() is None: r, w, e = select.select([sys.stdin, master_fd], [], []) if sys.stdin in r: d = os.read(sys.stdin.fileno(), 10240) os.write(master_fd, d) elif master_fd in r: o = os.read(master_fd, 10240) if o: os.write(sys.stdout.fileno(), o) # restore tty settings back termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)