Python 3 подробный контроль ввода-вывода другого процесса

В python 3 (на Linux или MacOSX10.8), как я могу получить родительский процесс, чтобы читать только приглашение (которое не включает \ n ), выпущенное подпроцессом, а не весь буфер до \ п ?

# program names.py
print("I am Joe.")                   #1print
name = input("What is your name? ")  #2prompt
print("Hi", name, "!")               #3print

# program parent.py (in python 3.3.0)
import subprocess
import sys
p = subprocess.Popen([sys.executable, "names.py"],
                      bufsize=0,
                      stdin =subprocess.PIPE,
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE,
                      shell=False,
                      universal_newlines=True
                    )
print(p.stdout.readline(), end='')
p.stdin.write("Sue\n")
# The next print will produce the output of 2prompt + 3print:
print(p.stdout.readline(), end='')

Когда я запускаю parent.py , он печатает:

I am Joe.
What is your name? Hi Sue !

Как изменить parent.py , чтобы он печатал:

I am Joe.
What is your name? 
Hi Sue !

То есть, как отдельно извлекать выходные данные, полученные с помощью подсказки и печати?

3
nl ja de
Возможно, это не совсем то, что вам нужно, но вы можете распечатать новую строку в начале «Привет» ...
добавлено автор Michael, источник

2 ответы

readline() reads from names.py until the next \n, where what you need is a "read as much as there is right now". Time is an additional factor here, since you basically have to detect, when names.py is waiting (expecting input).

В принципе, вам понадобится read() -операция с таймаутом. Вы можете запустить отдельный поток, который читает из байта names.py by byte в буфер. Затем вы можете join (timeout) этот поток и получить доступ к его буферу.

2
добавлено
примечание: если дочерний процесс буферизует приглашение, тогда чтение побайта не поможет (ваш процесс просто не увидит никакого вывода из дочернего элемента, пока он не сбросит его буферы). См. Почему бы просто не использовать pipe (popen ())?
добавлено автор jfs, источник
Да. Я предполагаю, что input() очищает буфер, как и любая программа перед запросом ввода.
добавлено автор Elmar Peise, источник

Если вы знаете, как выглядит приглашение, вы можете использовать строковые манипуляции, чтобы получить желаемый результат как @ Майкл предложил :

import sys
from subprocess import Popen, PIPE

p = Popen([sys.executable, "names.py"], stdin=PIPE, stdout=PIPE,
          universal_newlines=True)
Вывод = p.communicate("Sue\n")[0]
prompt = "name? "
print(Вывод.replace(prompt, prompt + "\n"))

Вывод

I am Joe.
What is your name? 
Hi Sue !

If you don't know how the prompt looks like then the timeout-based solution suggested by @Exp might not work if the child process uses block-buffering when it is run non-interactively. Though it does work for the names.py. Here's a timeout-based solution that uses select instead of threads to read the Вывод:

import os
import sys
from select import select
from subprocess import Popen, PIPE

timeout = 1 # seconds
with Popen([sys.executable, 'names.py'],
           stdin=PIPE, stdout=PIPE,  bufsize=0) as p:
    while True:
        ready = select([p.stdout], [], [], timeout)[0]
        if ready: # there is something to read
            data = os.read(p.stdout.fileno(), 512)
            if not data: # EOF
                break
            sys.stdout.buffer.write(data) # echo subprocess Вывод
        elif p.poll() is None: # timeout, but subprocess is still running
            print("") # print newline after the prompt
            p.stdin.write(b"Sue\n") # answer the prompt
        else: # subprocess exited
            break

It produces the same Вывод as the first code example after a delay.

В общем случае pexpect может использоваться для эмуляции интерактивного режима для подпроцесса.

Если вы знаете, как выглядит приглашение:

import sys
import pexpect

print(pexpect.run(sys.executable + " -mnames", events={r'name\? ': 'Sue\n'}))
# note: it echos our answer too (it can be avoided if necessary)

Вывод

I am Joe.
What is your name? Sue
Hi Sue !

Вот решение на основе тайм-аута, которое позволяет избежать повторения ответа:

import sys
import pexpect # pip install pexpect-u

child = pexpect.spawn(sys.executable + " -mnames", timeout=1)
child.logfile_read = sys.stdout # echo subprocess Вывод
child.expect(pexpect.TIMEOUT)
print("") # print newline after the prompt
child.setecho(False) # don't echo our answer
child.sendline('Sue')
child.expect(pexpect.EOF)
child.close()

Чтобы воспроизвести его с помощью subprocess , можно использовать модуль pty :

import os
import pty
import sys
from select import select
from subprocess import Popen, STDOUT

timeout = 1 # seconds
master_fd, slave_fd = pty.openpty()
with Popen([sys.executable, 'names.py'],
           stdin=slave_fd, stdout=slave_fd, stderr=STDOUT,
           bufsize=0) as p:
    while True:
        ready = select([master_fd], [], [], timeout)[0]
        if ready: # there is something to read
            data = os.read(master_fd, 512)
            if not data: # EOF
                break
            sys.stdout.buffer.write(data) # echo subprocess Вывод
        elif p.poll() is None: # timeout, but subprocess is still running
            # assume that child process waits for input after printing the prompt
            answer = b"Sue\n"
            os.write(master_fd, answer) # asnwer the prompt
            os.read(master_fd, len(answer)) # don't echo our answer
        else: # subprocess exited
            break
    os.close(slave_fd)
    os.close(master_fd)
0
добавлено
Python
Python
7 654 участник(ов)

Уютный чат для профессионалов, занимающихся поиском питоньих мудростей. Как не получить бан: https://t.me/ru_python/577926

Python beginners
Python beginners
4 449 участник(ов)

Вопросы про Python для чайников. Cпам и троллинг неприемлем. Не злоупотребляйте стикерами. Частозадаваемые вопросы: https://github.com/ru-python-beginners/faq/blob/master/README.md Статистика тут: https://grstats.me/chat/x4qym2k5uvfkr3al6at7

pro.python
pro.python
1 090 участник(ов)

Сообщество разработчиков под Python Создатель: @rodgelius

Rude Python
Rude Python
971 участник(ов)

Python без „девочек”, здесь матерятся и унижают Django. Not gay friendly. Правила: t.me/rudepython/114107 @rudepython | t.me/rudepython

rupython
rupython
509 участник(ов)

Группа создана с целью оперативного получения ответов на возникающие вопросы по разработке на яп python, смежные темы, а также человеческого общения. Приветствую!

Python-programming
Python-programming
266 участник(ов)

Чат группы вконтакте https://vk.com/python_community