Как я могу взаимодействовать с другой программой на Python? - PullRequest
2 голосов
/ 08 марта 2011

Я хочу написать скрипт Python, который запускает другую программу, читает выходные данные другой программы и манипулирует ими. Проблема в том, что эта программа запрашивает пароль, и я не могу понять, как его автоматически ввести. (Для целей этого сценария действительно не имеет значения, хранится ли пароль в виде простого текста в самом сценарии.) Я хочу сделать что-то вроде:

os.system('echo someinput | /var/local/bin/someprogram') 

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

К сожалению, у меня также есть некоторые ограничения относительно того, как я могу решить эту проблему. Во-первых, я застрял с Python 2.3 (поэтому я не могу использовать модуль подпроцесса). Во-вторых, я не могу установить какие-либо новые модули, (поэтому нет pexpect). К счастью, он не должен быть особенно переносимым, поэтому подходит решение только для Linux.

Я пытался выяснить модуль pty, так как он выглядит так, как будто он предлагает то, что мне нужно, но после нескольких часов борьбы с ним, я просто не могу понять, как заставить его работать так, как мне нужно .

Ответы [ 3 ]

3 голосов
/ 08 марта 2011

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

В зависимости от ваших потребностей, конечно, вы также можете просто использовать pexpect!

Вот мясо того, что я использовал в своем собственном проекте. Обратите внимание, что я не проверяю, завершается ли дочерний процесс; Сценарий должен был работать как демон, управляющий длительным процессом Java, поэтому мне никогда не приходилось иметь дело с кодами состояния. Надеюсь, однако, это даст вам большую часть того, что вам нужно.

import os
import pty
import select
import termios

child_pid, child_fd = pty.fork()

if not child_pid: # child process
    os.execv("/path/to/command", ["command", "arg1", "arg2"])

# disable echo
attr = termios.tcgetattr(child_fd)
attr[3] = attr[3] & ~termios.ECHO
termios.tcsetattr(child_fd, termios.TCSANOW, attr)

while True:
    # check whether child terminal has output to read
    ready, _, _ = select.select([child_fd], [], [])

    if child_fd in ready:
        output = []

        try:
            while True:
                s = os.read(child_fd, 1)

                # EOF or EOL
                if not s or s == "\n":
                    break

                # don't store carriage returns (no universal line endings)
                if not s == "\r":
                    output.append(s)
        except OSError: # this signals EOF on some platforms
            pass

        if output.find("Enter password:") > -1:
            os.write(child_fd, "password")
0 голосов
/ 08 марта 2011

Существует также другая реализация Python expect, которая легко поддерживает pty. Есть библиотека, которая упаковывает ssh и может отправлять пароли с ее помощью. Это модуль sshlib в Pycopia. Там есть метод входа в систему, который обрабатывает пароли. Он также использует модули ожидающих и обрабатывающих (proctools) из Pycopia. Первоначально я написал их для Python 2.2, поэтому они могут работать для вас. Но с другой стороны, они могут этого не делать, поскольку я свободно использовал другие новые функции Python с течением времени, которые могли закрасться.

Основная цель этих модулей состояла в том, чтобы сделать работу с подпроцессами, такими как вы описываете, более легкой и более "Pythonic".

0 голосов
/ 08 марта 2011

Вы можете использовать os.popen , который был перемещен в subprocess в версии 2.6, но все еще должен существовать в модуле os версии 2.3. Установите режим на 'w' и используйте close(), чтобы получить возвращаемое значение.

...