Взаимодействовать с консольным приложением Windows через Python - PullRequest
7 голосов
/ 14 июля 2009

Я использую Python 2.5 на Windows. Я хочу взаимодействовать с консольным процессом через Popen. У меня есть небольшой фрагмент кода:

p = Popen( ["console_app.exe"], stdin=PIPE, stdout=PIPE )
# issue command 1...
p.stdin.write( 'command1\n' )
result1 = p.stdout.read() # <---- we never return here
# issue command 2...
p.stdin.write( 'command2\n' )
result2 = p.stdout.read()

Я могу написать на стандартный ввод, но не могу прочитать на стандартный вывод. Я пропустил шаг? Я не хочу использовать p.communicate ("command") [0], поскольку он завершает процесс, и мне нужно динамически взаимодействовать с процессом с течением времени.

Заранее спасибо.

Ответы [ 5 ]

7 голосов
/ 14 июля 2009

Ваша проблема в том, что вы пытаетесь управлять интерактивным приложением.

stdout.read() продолжит чтение, пока не достигнет конца потока, файла или канала. К сожалению, в случае интерактивной программы канал закрывается только тогда, когда программа завершается; что никогда, если отправленная вами команда была чем-то отличным от "quit".

Вам нужно будет вернуться к чтению вывода подпроцесса построчно, используя stdout.readline(), и вам лучше будет узнать, когда программа готова принять команду, а когда выданная программа завершена и вы можете поставить новую. В случае такой программы, как cmd.exe, даже readline() будет недостаточно, поскольку строка, указывающая, что может быть отправлена ​​новая команда, не завершается новой строкой, поэтому придется анализировать вывод побайтно. Вот пример сценария, который запускает cmd.exe, ищет приглашение, затем выдает dir, а затем exit:

from subprocess import *
import re

class InteractiveCommand:
    def __init__(self, process, prompt):
        self.process = process
        self.prompt  = prompt
        self.output  = ""
        self.wait_for_prompt()

    def wait_for_prompt(self):
        while not self.prompt.search(self.output):
            c = self.process.stdout.read(1)
            if c == "":
                break
            self.output += c

        # Now we're at a prompt; clear the output buffer and return its contents
        tmp = self.output
        self.output = ""
        return tmp

    def command(self, command):
        self.process.stdin.write(command + "\n")
        return self.wait_for_prompt()

p      = Popen( ["cmd.exe"], stdin=PIPE, stdout=PIPE )
prompt = re.compile(r"^C:\\.*>", re.M)
cmd    = InteractiveCommand(p, prompt)

listing = cmd.command("dir")
cmd.command("exit")

print listing

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

from subprocess import *

p = Popen( ["cmd.exe"], stdin=PIPE, stdout=PIPE )
p.stdin.write("dir\n")
p.stdin.write("exit\n")

print p.stdout.read()
2 голосов
/ 15 июля 2009

Вы пытались заставить оконные линии окон? т.е.

p.stdin.write( 'command1 \r\n' )
p.stdout.readline()

UPDATE:

Я только что проверил решение для windows cmd.exe, и оно работает с readline (). Но у него есть одна проблема: stdout.readline блоков Popen . Так что, если приложение когда-нибудь вернет что-то без конца, ваше приложение застрянет навсегда.

Но есть обходной путь для этой проверки: http://code.activestate.com/recipes/440554/

0 голосов
/ 14 июля 2009

Возможно ли, что консольное приложение каким-то образом буферизует свой вывод, так что оно отправляется только на стандартный вывод, когда канал закрыт? Если у вас есть доступ к коду для консольного приложения, может, вам поможет вставка сброса после пакета выходных данных?

В качестве альтернативы, он по какой-то причине выполняет запись в stderr и вместо stdout?

Просто снова посмотрел на ваш код и подумал о чем-то другом, я вижу, вы отправляете "команду \ n". Может ли консольное приложение просто ждать символа возврата каретки вместо новой строки? Возможно, консольное приложение ожидает, пока вы отправите команду, прежде чем она выдаст какой-либо вывод.

0 голосов
/ 14 июля 2009

Была такая же проблема здесь. Я копался в исходном коде DrPython и украл решение wx.Execute () , которое работает нормально, особенно если ваш скрипт уже использует wx. Я никогда не находил правильное решение на платформе Windows, хотя ...

0 голосов
/ 14 июля 2009

Я думаю, вы можете попробовать использовать readline () вместо этого?

Редактировать: извините, недоразумение.

Может быть этот * вопрос 1006 * может вам помочь?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...