Перед отправкой ввода стандартного ввода дождитесь запроса от подпроцесса
У меня есть бинарный файл Linux x86, который запрашивает пароль и распечатывает, является ли пароль правильным или неправильным. Я хотел бы использовать Python для фазз ввода.
Ниже приведен скриншот того, как я запускаю двоичный файл, затем задаю ему строку "asdf" и получаю строку "неправильный"
Скриншот:
До сих пор я пытался использовать модуль подпроцесса Python3, чтобы
- запустить двоичный файл как подпроцесс
- получить подсказку для пароля
- отправить строку.
- получить ответ
Вот мой сценарий
p = subprocess.Popen("/home/pj/Desktop/L1/lab1",stdin=subprocess.PIPE, stdout=subprocess.PIPE)
print (p.communicate()[0])
результат выполнения этого скрипта
b'Please supply the code: \nIncorrect\n'
Я ожидаю получить только приглашение, однако двоичный файл также возвращает неправильный ответ, прежде чем я получу возможность отправить свой вклад.
Как я могу улучшить свой сценарий, чтобы успешно взаимодействовать с этим двоичным файлом?
1 ответ
Внимательно прочитайте документацию (выделение мое):
Popen.communicate(input=None)
Взаимодействовать с процессом: отправлять данные в stdin. Читайте данные из stdout и stderr, пока не будет достигнут конец файла. Подождите, пока процесс завершится. Необязательный входной аргумент должен быть строкой, которая будет отправлена дочернему процессу, или None, если никакие данные не должны быть отправлены дочернему процессу.
communicate()
возвращает кортеж(stdoutdata, stderrdata)
,Обратите внимание, что если вы хотите отправить данные в стандартный поток процесса, вам нужно создать объект Popen с
stdin=PIPE
, Точно так же, чтобы получить что-либо кроме None в кортеже результата, вам нужно датьstdout=PIPE
и / илиstderr=PIPE
тоже.
Итак, вы ничего не отправляете процессу и читаете все stdout
однажды.
В вашем случае вам не нужно ждать, пока приглашение отправит данные процессу, потому что потоки работают асинхронно: процесс получит ваши данные только тогда, когда попытается прочитать его. STDIN
:
In [10]: p=subprocess.Popen(("bash", "-c","echo -n 'prompt: '; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)
In [11]: p.communicate('foobar')
Out[11]: ('prompt: foobar\n', None)
Если по какой-либо причине вы настаиваете на ожидании приглашения (например, ваш процесс проверяет ввод перед приглашением, ожидая чего-то другого), вам необходимо прочитать STDOUT
вручную и ОЧЕНЬ осторожно, сколько вы читаете: начиная с Python file.read
блокирует, простой read()
заблокируется, потому что ожидает EOF, а подпроцесс не закрывается STDOUT
- таким образом, не производит EOF - пока не получит ваш вклад. Если длина входных или выходных данных может превышать длину буфера stdio (что вряд ли в вашем конкретном случае), вам также необходимо выполнять чтение stdout и запись stdin в отдельных потоках.
Вот пример использования pexpect
который позаботится об этом для вас (я использую pexpect.fdexpect
вместо pexpect.spawn
предложил в документации, потому что это работает на всех платформах):
In [1]: import pexpect.fdpexpect
In [8]: p=subprocess.Popen(("bash", "-c","echo -n 'prom'; sleep 5; echo 'pt: '; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)
In [10]: o=pexpect.fdpexpect.fdspawn(p.stdout.fileno())
In [12]: o.expect("prompt: ")
Out[12]: 0
In [16]: p.stdin.write("foobar") #you can communicate() here, it does the same as
# these 3 steps plus protects from deadlock
In [17]: p.stdin.close()
In [18]: p.stdout.read()
Out[18]: 'foobar\n'