Выполнение нескольких команд с помощью Popen.stdin - PullRequest
19 голосов
/ 29 января 2010

Я бы хотел выполнить несколько команд в отдельном приложении, запущенном из скрипта Python, используя каналы. Единственный способ надежно передать команды на стандартный ввод программы - использовать 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")

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

Ответы [ 4 ]

1 голос
/ 30 сентября 2011

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

Если это так, вы можете проверить библиотеку, подобную 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

0 голосов
/ 14 декабря 2011

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

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

0 голосов
/ 24 сентября 2011

Ваш код в вопросе должен работать как есть. Если это не так, то либо ваш фактический код отличается (например, вы можете использовать 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()
0 голосов
/ 29 января 2010

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

Итак, я бы предложил следующий подход:

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

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

...