2016-08-12 2 views
0

Я пытаюсь получить скрипт python на удаленном развертываемом встроенном Linux-устройстве для выполнения команды scp. Выполнение команды прост, но если целевой сервер не указан в файле «known_hosts», scp выдает предупреждение, с которым необходимо взаимодействовать. Я бил головой об этом в течение нескольких дней, и я не могу решить 2 проблемы.Python - обработка запроса на ввод в подпроцессах

Во-первых, я не могу получить неблокирующее считывание ответов от подпроцесса для правильной работы. В следующем коде select всегда возвращает ([], [], []), даже если я знаю, что могу читать из stderr (при условии, что генерируется предупреждение о доверенных файлах хоста).

cmdString = 'scp [email protected]:file localFile -i ~/.ssh/id_rsa' 

process = subprocess.Popen(shlex.split(cmdString), shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

while(process.poll() is None): 
    readable, writable, exceptional = select.select([process.stdout], [], [process.stderr], 1) 

    if not (readable or writable or exceptional): 
    # Always hits this condition, although adding an "os.read(...)" here 
    # will return the error prompt from process.stderr. 
    print "timeout condition" 
    else: 
    # Never makes it here 
    for e in exceptional: 
     stderr = os.read(process.stderr.fileno(), 256) 
     print stderr 
    for r in readable: 
     stdout = os.read(process.stdout.fileno(), 256) 
     print stdout 

Во-вторых, я не могу заставить подпроцесс продвигаться за пределы предупреждения путем подачи ввода через входной PIPE. Следующий код считывает код предупреждения из process.stderr, но затем зависает, пока я не нажму {enter} в моем терминале. Я попытался отправить «n», «n \ n» и «\ n», но ни один из них не приводит к продолжению выполнения подпроцесса (хотя все три шаблона работают при вводе вручную).

cmdString = 'scp [email protected]:file localFile -i ~/.ssh/id_rsa' 

process = subprocess.Popen(shlex.split(cmdString), shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

# Correctly grabs warning and displays it 
stderr = os.read(process.stderr.fileno(), 256) 
print stderr 

# Just in case there was some weird race condition or something 
time.sleep(0.5) 

# Doesn't ever seem to do anything 
process.stdin.write('\n') 

И, наконец, это имеет значение? Сначала я начал исследовать подпроцесс и PIPES, потому что я запускал scp, используя «os.system (cmdString)», который блокировал мой поток и заставлял меня разбираться с этой проблемой. Теперь, когда я использую подпроцесс, плохо ли просто отключить команду и позволить ей преуспеть или потерпеть неудачу? Неудачные подпроцессы в конечном итоге отмирают, или я могу в конечном итоге оказаться там, где у меня есть десятки или сотни скрытых попыток scp, но ожидающих ввода пользователем?

Спасибо!

ответ

0

Проблема в том, что scp не связывается с использованием stdin/stdout/stderr в этом случае, но напрямую через терминал.

Вы можете найти много похожих вопросов, а также способ справиться с этим, ища что-то вроде scp input на stackoverflow.

Начальные подпроцессы будут умирать только тогда, когда родители «протрубили» на выходе (stdout/stderr), и подпроцесс пытается что-то написать. В этом случае scp, вероятно, продолжит работу, потому что он использует терминал. Однако эти процессы не скрыты; вы можете легко увидеть их с помощью инструмента, например ps (и убить их с помощью kill или killall).

EDIT: Как вы упомянули вы имеете проблемы с различными библиотеками, возможно, следующий подход поможет:

import os, pty 

pid, fd = pty.fork() 
if pid == 0: 
    os.execvp('scp', ['scp', '[email protected]:file', ... ]) 
else: 
    while True: 
    s = os.read(fd, 1024) 
    print repr(s) 
    os.write(fd, 'something\n') 
+0

Спасибо, то понимание того, что он не использует стандартный STDIN/стандартный вывод/STDERR помогло много. Похоже, что «pexpect» может правильно управлять scp, и есть даже scp-аддон для paramiko, чтобы привести все это в мир python. К сожалению, «pexpect» не может создать виртуальный файл, который ему нужен, и у меня нет скомпилированной версии пакета криптографии, который требуется paramiko. Так как я работаю на стороннем встроенном устройстве с голой костью, изменение системных настроек, позволяющих создавать pty или кросс-компиляцию пакета сложно. – digitalosmosis

+0

@ digitalosmosis Добавлен пример «голых костей», который может вам помочь. – mweerden