我有一个sh文件,我需要在目标linux框中安装它。所以我正在为sh文件编写自动安装的过程,这需要用户提供大量的输入。例如,我做的第一件事./file.sh
它将显示一个大的paragaraph并要求用户按Enter
。我被困在这个地方。如何将关键数据发送到子流程。这是我尝试过的。
import subprocess
def runProcess(exe):
global p
p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while(True):
retcode = p.poll() #returns None while subprocess is running
line = p.stdout.readline()
yield line
if(retcode is not None):
break
for line in runProcess('./file.sh'.split()):
if '[Enter]' in line:
print line + 'got it'
p.communicate('\r')
如果我的理解是错误的,请纠正我,请原谅我是否重复。
答案 0 :(得分:2)
如果您需要发送一堆换行符,则需要:
stdin
的{{1}}是管道您当前的代码都没有。可能有用的东西(假设他们不使用需要在tty中直接交互的API,而不仅仅是阅读Popen
):
stdin
对于需要自定义响应的情况,您需要在父线程和馈线线程之间添加通信,这会使这更加丑陋,并且只有在子进程正确刷新其输出时才有效即使未连接到终端,它也会提示您。您可以执行以下操作来定义全局队列:
import subprocess
import threading
def feednewlines(f):
try:
# Write as many newlines as it will take
while True:
f.write(b'\n') # Write newline, not carriage return
f.flush() # Flush to ensure it's sent as quickly as possible
except OSError:
return # Done when pipe closed/process exited
def runProcess(exe):
global p
# Get stdin as pipe too
p = subprocess.Popen(exe, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Use thread to just feed as many newlines as needed to stdin of subprocess
feeder = threading.Thread(target=feednewlines, args=(p.stdin,))
feeder.daemon = True
feeder.start()
# No need to poll, just read until it closes stdout or exits
for line in p.stdout:
yield line
p.stdin.close() # Stop feeding (causes thread to error and exit)
p.wait() # Cleanup process
# Iterate output, and echo when [Enter] seen
for line in runProcess('./file.sh'.split()):
if '[Enter]' in line:
print line + 'got it'
然后将进纸器功能更改为:
import queue # Queue on Python 2
feederqueue = queue.Queue()
并将全局代码更低地更改为:
def feednewlines(f):
try:
while True:
f.write(feederqueue.get())
f.flush()
except OSError:
return
等
答案 1 :(得分:1)
当命令行程序在后台运行时,它们在终端中运行时运行方式不同。如果程序附加到终端,则它们以交互式线路模式运行,期望用户交互。如果stdin是文件或管道,则它们以块模式运行,其中写入被延迟,直到缓冲某个块大小。您的程序永远不会看到[Enter]
提示符,因为它使用管道并且数据仍在子进程输出缓冲区中。
python pexpect
模块通过模拟终端并允许您通过一系列" expect"来解决这个问题。语句。
假设我们想要运行一个测试程序
#!/usr/bin/env python3
data = input('[Enter]')
print(data)
它非常无聊。它会提示输入数据,打印数据然后退出。我们可以使用pexpect
运行它
#!/usr/bin/env python3
import pexpect
# run the program
p = pexpect.spawn('./test.py')
# we don't need to see our input to the program echoed back
p.setecho(False)
# read lines until the desired program output is seen
p.expect(r'\[Enter\]')
# send some data to the program
p.sendline('inner data')
# wait for it to exit
p.expect(pexpect.EOF)
# show everything since the previous expect
print(p.before)
print('outer done')