Запуск интерактивной команды из Python

У меня есть скрипт, который я хочу запустить из Python (2.6.5), который следует логике ниже:

Prompt user for password. Looks like ("Enter password: ") (*Note: Input does not echo to screen) Output irrelevant information Prompt user for response ("Blah Blah filename.txt blah blah (Y/N)?: ")

Последняя строка подсказки содержит текст, который мне нужно проанализировать (filename.txt). Предоставленный ответ не имеет значения (программа может фактически завершиться, не предоставив его, пока я могу разобрать строку)

Мои требованияsomewhat похожий наОбертывание интерактивного приложения командной строки в сценарии Python, но ответы там кажутся немного запутанными, и мой по-прежнему зависает, даже когда ОП упоминает, что это не для него.

Оглядываясь вокруг, я пришел к выводу, чтоsubprocess это лучший способ сделать это, но у меня есть несколько проблем. Вот моя линия Попен:

p = subprocess.Popen("cmd", shell=True, stdout=subprocess.PIPE, 
stderr=subprocess.STDOUT, stdin=subprocess.PIPE)

When I call a read() or readline() on stdout, the prompt is printer to the screen and it hangs.

If I call a write("password\n") for stdin, the prompt is written to the screen and it hangs. The text in write() is not written (I don't the cursor move the a new line).

If I call p.communicate("password\n"), same behavior as write()

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

 user152159712 июл. 2012 г., 21:49
@ColinDunklau Я надеялся свести к минимуму использование внешних модулей
 Colin Dunklau12 июл. 2012 г., 20:15
Вы должны посмотреть на pexpect:noah.org/wiki/pexpect
 user152159712 июл. 2012 г., 21:44
@Джоран, ха-ха, извини. Это то, что я имел в виду.
 Joran Beasley12 июл. 2012 г., 20:16
Я думаю, что вам нужно написать в стандартный вывод и читать из стандартного ввода ... а не наоборот, как вы положили выше

Ответы на вопрос(2)

Использование потоков может быть немного излишним для простых задач. Вместо os.spawnvpe можно использовать. Это будет вызывать сценарий оболочки как процесс. Вы сможете интерактивно общаться со сценарием. В этом примере я передал пароль в качестве аргумента, очевидно, это не очень хорошая идея.

import os
import sys
from getpass import unix_getpass

def cmd(cmd):
    cmd = cmd.split()
    code = os.spawnvpe(os.P_WAIT, cmd[0], cmd, os.environ)
    if code == 127:
        sys.stderr.write('{0}: command not found\n'.format(cmd[0]))
    return code

password = unix_getpass('Password: ')
cmd_run = './run.sh --password {0}'.format(password)
cmd(cmd_run)

pattern = raw_input('Pattern: ')
lines = []
with open('filename.txt', 'r') as fd:
    for line in fd:
        if pattern in line:
            lines.append(line)

# manipulate lines

Если вы общаетесь с программой, которая порождает подпроцесс, вы должны проверитьНеблокирующее чтение на подпроцесс. PIPE в Python, У меня была похожая проблема с моим приложением, и я обнаружил, что использование очередей - лучший способ поддерживать постоянную связь с подпроцессом.

Что касается получения значений от пользователя, вы всегда можете использовать встроенную функцию raw_input () для получения ответов, а для паролей попробуйте использоватьgetpass модуль для получения не повторяющихся паролей от вашего пользователя. Затем вы можете проанализировать эти ответы и записать их в свой подпроцесс & apos; STDIN.

В итоге я сделал что-то похожее на следующее:

import sys
import subprocess
from threading  import Thread

try:
    from Queue import Queue, Empty
except ImportError:
    from queue import Queue, Empty  # python 3.x


def enqueue_output(out, queue):
    for line in iter(out.readline, b''):
        queue.put(line)
    out.close()


def getOutput(outQueue):
    outStr = ''
    try:
        while True: #Adds output from the Queue until it is empty
            outStr+=outQueue.get_nowait()

    except Empty:
        return outStr

p = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, universal_newlines=True)

outQueue = Queue()
errQueue = Queue()

outThread = Thread(target=enqueue_output, args=(p.stdout, outQueue))
errThread = Thread(target=enqueue_output, args=(p.stderr, errQueue))

outThread.daemon = True
errThread.daemon = True

outThread.start()
errThread.start()

try:
    someInput = raw_input("Input: ")
except NameError:
    someInput = input("Input: ")

p.stdin.write(someInput)
errors = getOutput(errQueue)
output = getOutput(outQueue)

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

Ваш ответ на вопрос