Запуск интерактивного Bash с помощью popen и выделенного TTY Python

Мне нужно запустить интерактивный экземпляр Bash в отдельном процессе на Python с его собственным выделенным TTY (я не могу использовать pexpect). Я использовал этот фрагмент кода, который я обычно вижу в подобных программах:

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) 

Но когда я запускаю его, я получаю следующий вывод:

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

Трассировка пробега показывает некоторые ошибки:

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

Фрагмент кода кажется довольно простым, Bash не получает чего-то, что ему нужно? что может быть проблемой здесь?

  • Можете ли вы обмануть isatty AND log stdout и stderr отдельно?
  • Отфильтровать команду, которая нуждается в терминале в модуле подпроцесса Python
  • включение tty в сеансе ssh
  • Почему печать на stdout так медленно? Можно ли его ускорить?
  • Выполнить команду и получить ее stdout, stderr отдельно в почти реальном времени, как в терминале
  • Почему мне нужно дважды набирать ctrl-d?
  • Терминал перепутался (не отображая новые строки) после запуска скрипта Python
  • 3 Solutions collect form web for “Запуск интерактивного Bash с помощью popen и выделенного TTY Python”

    Это решение для запуска интерактивной команды в подпроцессе. Он использует псевдотерминал, чтобы сделать stdout неблокирующим (также для некоторой команды требуется устройство tty, например bash). он использует select для обработки ввода и вывода для подпроцесса.

     #!/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) 

    Это решение, которое работало для меня в конце (как было предложено 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 

    вам нужно будет передать ввод для чтения, а затем распечатать x.

    Python - лучший язык программирования в мире.