使用Python子过程复制过程输出

问题描述 投票:1回答:1

我正在尝试从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脚本运行命令时,是否存在一种安全的方法来在命令行中逐步显示命令的确切输出?

python subprocess output
1个回答
0
投票
  1. 始终将openSTDIN作为管道使用,如果不使用它,请立即将其关闭。

  2. p.stdout.read()将阻塞,直到关闭管道为止,因此您的轮询代码在这里没有任何用处。需要修改。

  3. 我建议不要使用shell = True

  4. 代替* .readline(),尝试使用* .read(1)并等待“ \ n”

当然,您可以在Python中做您想做的,问题是如何做。因为子进程可能对故障的输出有不同的想法,那就是麻烦开始了。例如。该过程可能希望在另一端显式地建立一个终端,而不是您的过程。还是很多这样简单的废话。同样,缓冲也会引起问题。您可以尝试以无缓冲模式启动Python进行检查。 (/ usr / bin / python -U)

如果没有任何效果,则使用pexpect自动化库而不是子进程。

© www.soinside.com 2019 - 2024. All rights reserved.