Подтвердить что ты не робот

Выполнение нескольких команд с помощью Popen.stdin

Я хотел бы выполнить несколько команд в автономном приложении, запущенном с python script, используя каналы. Единственный способ, которым я мог надежно передать команды на stdin программы, - использовать Popen.communicate, но он закрывает программу после выполнения команды. Если я использую Popen.stdin.write, то команда выполняет только 1 раз из 5 или около того, она не работает надежно. Что я делаю неправильно?

Чтобы разработать немного:

У меня есть приложение, которое слушает stdin для команд и выполняет их по строкам. Я хотел бы иметь возможность запускать приложение и передавать ему различные команды на основе взаимодействия пользователей с графическим интерфейсом. Это простой пример:

import os, string
from subprocess import Popen, PIPE

command = "anApplication" 
process = Popen(command, shell=False, stderr=None, stdin=PIPE)

process.stdin.write("doSomething1\n")
process.stdin.flush()
process.stdin.write("doSomething2\n")
process.stdin.flush()

Я ожидаю увидеть результат обеих команд, но я не получаю никакого ответа. (Если я выполняю одну из строк Popen.write несколько раз, она иногда работает.)

И если я выполняю:

process.communicate("doSomething1")

работает отлично, но приложение завершается.

4b9b3361

Ответ 1

Если я правильно понимаю вашу проблему, вы хотите взаимодействовать (то есть отправлять команды и читать ответы) с помощью консольного приложения.

Если это так, вы можете проверить библиотеку, подобную Expect, такую ​​как pexpect для Python: http://pexpect.sourceforge.net

Это упростит вашу жизнь, потому что она позаботится о синхронизации, о проблеме, которую также описывает ddaa. Смотрите также: http://www.noah.org/wiki/Pexpect#Q:_Why_not_just_use_a_pipe_.28popen.28.29.29.3F

Ответ 2

Ваш код в вопросе должен работать так, как есть. Если это не так, либо ваш фактический код отличается (например, вы можете использовать stdout=PIPE, который может изменить поведение буферизации для детей) или может указывать на ошибку в самом дочернем приложении, например ошибка чтения в Python 2, т.е. ваш вход правильно отправляется родительским процессом, но он застревает в внутреннем входном буфере.

На моем компьютере Ubuntu работает следующее:

#!/usr/bin/env python
import time
from subprocess import Popen, PIPE

LINE_BUFFERED = 1

#NOTE: the first argument is a list
p = Popen(['cat'], bufsize=LINE_BUFFERED, stdin=PIPE,
          universal_newlines=True)
with p.stdin:
    for cmd in ["doSomething1\n", "doSomethingElse\n"]:
        time.sleep(1) # a delay to see that the commands appear one by one
        p.stdin.write(cmd)
        p.stdin.flush() # use explicit flush() to workaround
                        #   buffering bugs on some Python versions
rc = p.wait()

Ответ 3

Реальная проблема здесь в том, является ли приложение буферизацией его вывода, и если это то, что вы можете сделать, чтобы остановить его. Предположительно, когда пользователь генерирует команду и нажимает кнопку в вашем графическом интерфейсе, вы хотите видеть результат этой команды, прежде чем вам потребуется ввести следующий пользователь.

К сожалению, вы ничего не можете сделать на стороне клиента subprocess.Popen, чтобы убедиться, что, когда вы передали приложение, команда, которая проверяет, что все выходные данные очищены до конечного адресата. Вы можете называть flush() все, что вам нравится, но если оно не делает то же самое, и вы не можете это сделать, то вы обречены на поиск обходных решений.

Ответ 4

Похоже, ваше приложение обрабатывает входные данные из трубы странным образом. Это означает, что он не получит все команды, которые вы отправляете, пока не закроете трубку.

Поэтому подход, который я хотел бы предложить, - это просто:

process.stdin.write("command1\n")
process.stdin.write("command2\n")
process.stdin.write("command3\n")
process.stdin.close()

Не похоже, что ваша программа Python считывает выходные данные из приложения, поэтому не имеет значения, посылаете ли вы все команды одновременно.