2016-08-12 30 views
0

我试图在远程部署的嵌入式Linux设备上获取python脚本来执行scp命令。执行该命令很简单,但如果目标服务器未在'known_hosts'文件中列出,则scp会引发需要与之交互的警告。几天来,我的头反对这一点,我无法解决2个问题。Python - 处理子进程中的输入提示

首先,我无法从子流程中获取非阻塞读取的响应,以正常工作。在下面的代码中,即使当我知道我可以从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 

其次,我无法通过输入管道输入输入来使子进程超出警告范围。以下代码读取来自process.stderr的警告代码,但之后会挂起,直到我在终端中点击{enter}。我尝试发送“n”,“n \ n”和“\ n”,但没有任何一个会导致子进程继续执行(尽管手动输入时全部3种模式都有效)。

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,因为我使用“os.system(cmdString)”来运行scp,它阻塞了我的线程并迫使我处理这个问题。现在我正在使用子进程,只是启动命令并让它成功或失败,这不好吗?失败的子进程最终是否会终止,或者最终我会在哪里运行数十或数百个隐藏的scp尝试,但等待用户输入?

谢谢!

回答

0

在这种情况下,问题可能是scp不使用stdin/stdout/stderr进行通信,而是直接通过终端进行通信。

你可以通过在stackoverflow上搜索诸如scp input之类的东西来找到很多类似的问题以及处理它的方法。

只有父母“输送”输出(stdout/stderr)并且子进程试图写入内容时,启动的子进程才会死亡。在这种情况下,scp可能会继续运行,因为它使用的是终端。尽管这些过程并不真正隐藏,你可以用ps这样的工具轻松看到它们(并用killkillall将它们杀死)。

编辑:正如你所说,你有各种库的问题,也许下面的方法将帮助:

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

谢谢,它不使用标准的标准输入/输出/标准错误的见解帮了不少忙。它看起来像“pexpect”可以正确地驱动scp,并且甚至还有一个用于paramiko的scp插件,可以将它带入Python世界。 不幸的是,“pexpect”不能创建它所需要的虚拟pty,我没有paramiko需要的密码包的编译版本。由于我正在开发第三方嵌入式设备,因此更改系统设置以允许创建pty或交叉编译包是很困难的。 – digitalosmosis

+0

@digitalosmosis增加了一个“裸骨”的例子,可以帮助你。 – mweerden