我正在尝试从Python自动化脚本中运行“ docker-compose pull”,并逐步显示与Docker命令直接从外壳运行时将输出的输出相同的输出。此命令为系统中找到的每个Docker映像打印一行,并在该Docker映像的最新版本下载完成后,在每行末尾递增“ done”。我首先尝试通过subprocess.poll()和(阻塞)readline()调用获取命令输出:
import shlex
import subprocess
def run(command, shell=False):
p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell)
while True:
# print one output line
output_line = p.stdout.readline().decode('utf8')
error_output_line = p.stderr.readline().decode('utf8')
if output_line:
print(output_line.strip())
if error_output_line:
print(error_output_line.strip())
# check if process finished
return_code = p.poll()
if return_code is not None and output_line == '' and error_output_line == '':
break
if return_code > 0:
print("%s failed, error code %d" % (command, return_code))
run("docker-compose pull")
代码被卡在第一个(阻塞的)readline()调用中。然后我尝试做同样的事情而不阻塞:
import select
import shlex
import subprocess
import sys
import time
def run(command, shell=False):
p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell)
io_poller = select.poll()
io_poller.register(p.stdout, select.POLLIN)
io_poller.register(p.stderr, select.POLLIN)
while True:
# poll IO for output
io_events_list = []
while not io_events_list:
time.sleep(1)
io_events_list = io_poller.poll(0)
# print new output
for event in io_events_list:
if event[0] == sys.stdout.fileno():
output_str = p.stdout.read().decode('utf8')
print(output_str, end="")
if event[0] == sys.stderr.fileno():
error_output_str = p.stderr.read().decode('utf8')
print(error_output_str, end="")
# check if process finished
# when subprocess finishes, iopoller.poll(0) returns a list with 2 select.POLLHUP events
# (one for stdout, one for stderr) and does not enter in the inner loop
return_code = p.poll()
if return_code is not None:
break
if return_code > 0:
print("%s failed, error code %d" % (command, return_code))
run("docker-compose pull")
io_poller.poll()从不返回任何IO事件。
这两种方法都可以与带有更简单输出(例如“ ls”)的命令配合使用。我做错了吗,或者问题可能与该Docker命令如何逐步打印到屏幕有关?通过Python脚本运行命令时,是否存在一种安全的方法来在命令行中逐步显示命令的确切输出?
始终将openSTDIN作为管道使用,如果不使用它,请立即将其关闭。
p.stdout.read()将阻塞,直到关闭管道为止,因此您的轮询代码在这里没有任何用处。需要修改。
我建议不要使用shell = True
代替* .readline(),尝试使用* .read(1)并等待“ \ n”
当然,您可以在Python中做您想做的,问题是如何做。因为子进程可能对故障的输出有不同的想法,那就是麻烦开始了。例如。该过程可能希望在另一端显式地建立一个终端,而不是您的过程。还是很多这样简单的废话。同样,缓冲也会引起问题。您可以尝试以无缓冲模式启动Python进行检查。 (/ usr / bin / python -U)
如果没有任何效果,则使用pexpect自动化库而不是子进程。