我试图在远程部署的嵌入式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尝试,但等待用户输入?
谢谢!
谢谢,它不使用标准的标准输入/输出/标准错误的见解帮了不少忙。它看起来像“pexpect”可以正确地驱动scp,并且甚至还有一个用于paramiko的scp插件,可以将它带入Python世界。 不幸的是,“pexpect”不能创建它所需要的虚拟pty,我没有paramiko需要的密码包的编译版本。由于我正在开发第三方嵌入式设备,因此更改系统设置以允许创建pty或交叉编译包是很困难的。 – digitalosmosis
@digitalosmosis增加了一个“裸骨”的例子,可以帮助你。 – mweerden