当前位置: 首页 > 面试题库 >

如何在不失真的情况下打印和显示子进程stdout和stderr输出?

黄骏喆
2023-03-14
问题内容

也许在以太坊里有人可以帮助我。(我在SO上看到了许多与此类似的问题,但是没有一个解决标准输出和标准错误的问题,也没有处理类似于我的情况的问题,因此是这个新问题。)

我有一个python函数,它将打开一个子进程,等待其完成,然后输出返回码,以及标准输出和标准错误管道的内容。在进程运行时,我还要在填充时显示两个管道的输出。我的第一次尝试导致了这样的事情:

process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

stdout = str()
stderr = str()
returnCode = None
while True:
    # collect return code and pipe info
    stdoutPiece = process.stdout.read()
    stdout = stdout + stdoutPiece
    stderrPiece = process.stderr.read()
    stderr = stderr + stderrPiece
    returnCode = process.poll()

    # check for the end of pipes and return code
    if stdoutPiece == '' and stderrPiece == '' and returnCode != None:
        return returnCode, stdout, stderr

    if stdoutPiece != '': print(stdoutPiece)
    if stderrPiece != '': print(stderrPiece)

但是有几个问题。因为read()读取直到an EOF,所以while循环的第一行直到子进程关闭管道才返回。

我可以替换为read()read(int)但是打印输出失真,在读取字符的末尾切断。我可以readline()代替它,但是当同时发生很多输出和错误时,打印输出会因输出和错误的交替出现而失真。

也许有一个read-until-end-of-buffer()我不知道的变体?还是可以实施?

也许最好按照另一个帖子的答案中的sys.stdout建议实现一个包装器?但是,我只想在此函数中使用包装器。

社区还有其他想法吗?

感谢您的帮助!:)

编辑 :解决方案确实应该是跨平台的,但是如果您没有想法,请与他人分享以保持头脑风暴。


问题答案:

使用来使管道成为非阻塞状态fcntl.fcntl,并使用select.select来等待数据在任一管道中变为可用。例如:

# Helper function to add the O_NONBLOCK flag to a file descriptor
def make_async(fd):
    fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)

# Helper function to read some data from a file descriptor, ignoring EAGAIN errors
def read_async(fd):
    try:
        return fd.read()
    except IOError, e:
        if e.errno != errno.EAGAIN:
            raise e
        else:
            return ''

process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
make_async(process.stdout)
make_async(process.stderr)

stdout = str()
stderr = str()
returnCode = None

while True:
    # Wait for data to become available 
    select.select([process.stdout, process.stderr], [], [])

    # Try reading some data from each
    stdoutPiece = read_async(process.stdout)
    stderrPiece = read_async(process.stderr)

    if stdoutPiece:
        print stdoutPiece,
    if stderrPiece:
        print stderrPiece,

    stdout += stdoutPiece
    stderr += stderrPiece
    returnCode = process.poll()

    if returnCode != None:
        return (returnCode, stdout, stderr)

请注意,fcntl仅在包括Cygwin的类Unix平台上可用。

如果您需要它在不使用Cygwin的Windows上运行,那是可行的,但难度要大得多。您必须:

  • 使用pywin32库调用本机Win32 API
  • SetNamedPipeHandleState与withPIPE_NOWAIT一起使用以使stdout和stderr管道不阻塞
  • 使用WaitForMultipleObjects而不是select等待数据可用
  • 使用ReadFile读取数据


 类似资料:
  • 问题内容: 我想捕获并显示通过Python的子流程调用的流程的输出。 我以为我可以将文件状对象作为参数stdout和stderr传递 我可以看到它访问了属性-因此它正在处理对象。但是,永远不会调用该方法。我的方法是否完全无效或我只是缺少什么? 更新: 我还想工作的是ANSI控制字符,用于移动光标并覆盖以前的输出内容。我不知道这是否是正确的术语,但这是我的意思的一个示例:我正在尝试使一些GIT自动化

  • 问题内容: 我有一些脚本应该已经停止运行,但是永远挂在身边。我是否可以通过某种方式以一种可读的方式弄清楚它们正在向STDOUT和STDERR写入什么内容? 例如,我尝试执行以下操作: 但这确实不起作用。无论如何,这是一个远射。 还有其他想法吗? 就其本身而言,它很冗长且难以理解。 注意:我 只 对它们的输出感兴趣,而对其他任何东西都不感兴趣。我有能力自己弄清其他事情;这个问题只集中在获得访问std

  • 问题内容: 我正在尝试修复这段代码,该代码是从具有车牌号和车主列表(该格式)的哈希图进行打印的。我试图通过printOwners()仅打印出所有者;但是我不能不打印重复的东西。 我已经玩了一段时间,但似乎无法跳过重复项。 这是我的代码: 问题答案: 要删除重复项,请使用: 或者使用Java 8 和方法:

  • 此方法的输入为“9876548” 我不要结尾的“9876548”。 (叠加流格式不会全部 实现一个递归方法 printDigits,该方法将整数 num 作为参数,并以相反的顺序打印其数字,每行一个数字。 谢谢大家的帮助!

  • 问题内容: 我有一个Python脚本正在使用我的雇主提供的某些封闭式Python函数(即我无法编辑这些函数)。当我调用这些函数时,它们会将输出打印到我想抑制的Linux终端上。我试过通过重定向标准输出/标准错误; 但这无法捕获输出。我认为我通过Python调用的函数(上面的rogue_function())实际上是经过编译的C代码的包装程序,它们实际上是在进行打印。 有谁知道一种方法可以对某个函数

  • 问题内容: 我想通过python从目录中调用脚本(它们是可执行的shell脚本)。 到现在为止还挺好: 现在我想要的是:假设我有一个具有启动功能的bash脚本。我从那里打电话 回声“某事” 现在,我想看看sys.stdout和退出代码上的回显。我相信您可以使用.communicate()执行此操作,但是我的操作不符合我的预期。 我究竟做错了什么? 任何帮助深表感谢 问题答案: 授予http://d