Это не будет работать для длинных выходов: subprocess.call
будет блокироваться после заполнения буфера PTY. Вот почему subprocess.communicate
существует, но это не сработает с PTY.
Стандартный/Самым простым решением является использование внешнего модуля pexpect, который использует PTYs внутренне, например,
pexpect.spawn("/bin/ls --color=auto").read()
даст вам ls
выход с цветовыми кодами.
Если вы хотите придерживаться subprocess
, то вы должны использовать subprocess.Popen
по указанной выше причине. Вы правы в своем предположении, что, пройдя 1000
, вы читаете не более 1000 байт, поэтому вам придется использовать цикл. os.read
блокирует, если нет ничего, что можно было бы прочитать и ждет появления данных. Улов заключается в том, как распознать, когда процесс был прерван: в этом случае вы знаете, что больше данных не поступит. Следующий звонок os.read
будет блокироваться навсегда. К счастью, операционная система помогает вам обнаружить эту ситуацию: если все дескрипторы файлов на псевдотерминале, которые могут быть использованы для записи, будут закрыты, то os.read
либо вернет пустую строку, либо вернет ошибку, в зависимости от ОС. Вы можете проверить это условие и выйти из цикла, когда это произойдет. Теперь последняя часть понимания следующего кода заключается в том, чтобы понять, как открытые файловые дескрипторы и subprocess
идут вместе: subprocess.Popen
внутренне вызывает fork()
, который дублирует текущий процесс, включая все открытые файловые дескрипторы, а затем в рамках одного из двух путей выполнения вызовов exec()
, который завершает текущий процесс в пользу нового. В другом пути выполнения управление возвращается к вашему сценарию Python. Поэтому после вызова subprocess.Popen
есть два действительные файловые дескрипторы для подчиненного конца PTY: один принадлежит к порожденному процессу, один для вашего скрипта Python. Если вы закроете свой, то единственный дескриптор файла, который может быть использован для отправки данных на главный конец, принадлежит порожденному процессу. После его завершения он закрывается, и PTY переходит в состояние, когда вызовы read
на главном конце не работают.
Вот код:
import os
import pty
import subprocess
master, slave = pty.openpty()
process = subprocess.Popen("/bin/ls --color", shell=True, stdout=slave,
stdin=slave, stderr=slave, close_fds=True)
os.close(slave)
output = []
while True:
try:
data = os.read(master, 1024)
except OSError:
break
if not data:
break
output.append(data) # In Python 3, append ".decode()" to os.read()
output = "".join(output)
хмм, я попробовал, и это не работает. Он просто идет 'while True:' навсегда. –
Я обновил вызов «Popen» таким образом, что порожденный процесс * только * видит PTY.Если это не изменит ситуацию, то: какую ОС вы используете? Вы уверены, что скрипт, который вы пытаетесь запустить, завершает/не блокирует, потому что он ожидает ввода пользователем? Прерывает ли мой пример как-либо, или он работает навсегда? Можете ли вы придумать пример команды, которую вы готовы поделиться, где цикл не заканчивается? С помощью какой версии Python? (Для целей отладки попробуйте добавить 'print repr (output [-1])' внутри цикла while.) – Phillip
Я запускаю OS X 10.12, Python 2.7.10. Даже с вашим примером, '/ bin/ls --color', это stucks. 'print repr (output [-1])' бесконечно пишет '' '' - просто пустую строку. –