Внимательно прочитайте документацию (выделено мной):
Popen.communicate(input=None)
Взаимодействовать с процессом: Отправитьданные в стандартный вводЧитайте данные из stdout и stderr, пока не будет достигнут конец файла.Подождите, пока процесс завершится.Необязательный входной аргумент должен быть строкой для отправки дочернему процессу , или None, если никакие данные не должны быть отправлены дочернему процессу.
communicate()
возвращает кортеж (stdoutdata, stderrdata)
.
Обратите внимание, что если вы хотите отправить данные в стандартный поток процесса, вам нужно создать объект Popen с stdin=PIPE
.Точно так же, чтобы получить что-то кроме None в кортеже результата, вам нужно указать также stdout=PIPE
и / или stderr=PIPE
.
Итак, вы ничего не отправляете процессу и читаете все из stdout
сразу.
В вашем случае вам на самом деле не нужно ждать запроса на отправку данных процессу, потому что потоки работают асинхронно:процесс получит ваш ввод, только когда попытается прочитать его STDIN
:
In [10]: p=subprocess.Popen(("bash", "-c","echo -n 'prompt: '; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)
In [11]: p.communicate('foobar')
Out[11]: ('prompt: foobar\n', None)
Если вы настаиваете на ожидании приглашения по какой-либо причине (например, ваш процесс проверяет ввод перед запросом,тоже, ожидая чего-то другого), вам нужно прочитать STDOUT
вручную и быть ОЧЕНЬ осторожным, сколько вы читаете : поскольку Python file.read
блокирует, простой read()
будет тупиком, потому что он ожидает EOFи подпроцесс не закрывается STDOUT
- таким образом, не производит EOF - пока не получит от вас информацию.Если длина входных или выходных данных может превышать длину буфера stdio (маловероятно в вашем конкретном случае), вам также необходимо выполнять чтение stdout и запись stdin в отдельных потоках .
ВотПример использования pexpect
, который позаботится об этом для вас (я использую pexpect.fdexpect
вместо pexpect.spawn
, предложенного в документе , потому что он работает на всех платформах):
In [1]: import pexpect.fdpexpect
In [8]: p=subprocess.Popen(("bash", "-c","echo -n 'prom'; sleep 5; echo 'pt: '; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)
In [10]: o=pexpect.fdpexpect.fdspawn(p.stdout.fileno())
In [12]: o.expect("prompt: ")
Out[12]: 0
In [16]: p.stdin.write("foobar") #you can communicate() here, it does the same as
# these 3 steps plus protects from deadlock
In [17]: p.stdin.close()
In [18]: p.stdout.read()
Out[18]: 'foobar\n'