运行命令并像在终端中一样近实时地分别获取其stdout,stderr

运行命令并像在终端中一样近实时地分别获取其stdout,stderr,第1张

运行命令并像在终端中一样近实时地分别获取其stdout,stderr

可以分别记录正在运行的程序的stdout和stderr。

您无法使用,

pexpect
因为stdout和stderr都使用相同的
pty
方法,之后无法将它们分开。

可以实时查看正在运行的程序的stdout和stderr,这样,如果子进程挂起,则用户可以看到。(即,我们不等待执行完成再将stdout /
stderr打印给用户)

如果子进程的输出不是tty
,则可能使用块缓冲,因此,如果子进程的输出不大
,则不会是“实时”,
例如,如果缓冲区为4K,则您的父级直到子进程打印4K字符并且缓冲区溢出或显式刷新(在子进程内部),Python进程才会看到任何内容。该缓冲区位于子进程内部,没有标准的方法可以从外部进行管理。这是显示stdio缓冲区和

command1 | command2
shell管道的管道缓冲区的图片:

正在运行的程序不知道它是通过python运行的,因此不会做意外的事情(例如,将其输出分块而不是实时打印,或者退出,因为它需要一个终端来查看其输出)。

看来,您的意思相反,即,如果将输出重定向到管道(

stdout=PIPE
在Python中使用),则子进程可能会对其输出进行分块,而不是尽快刷新每条输出行。这意味着默认的线程或异步解决方案将无法正常使用。

有几种解决方法:

  • 该命令可以接受诸如

    grep --line-buffered
    或的命令行参数
    python -u
    来禁用块缓冲。

  • stdbuf
    适用于某些程序,即,您可以
    ['stdbuf', '-oL', '-eL'] + command
    使用上面的线程或asyncio解决方案运行,并且应该分别获得stdout,stderr和行,并且这些行应几乎实时显示:

    #!/usr/bin/env python3

    import os
    import sys
    from select import select
    from subprocess import Popen, PIPE

    with Popen([‘stdbuf’, ‘-oL’, ‘-e0’, ‘curl’, 'www.google.com’],
    stdout=PIPE, stderr=PIPE) as p:
    readable = {
    p.stdout.fileno(): sys.stdout.buffer, # log separately
    p.stderr.fileno(): sys.stderr.buffer,
    }
    while readable:
    for fd in select(readable, [], [])[0]:
    data = os.read(fd, 1024) # read available
    if not data: # EOF
    del readable[fd]
    else:
    readable[fd].write(data)
    readable[fd].flush()

  • 最后,您可以尝试使用

    pty
    +
    select
    两个解决方案
    pty

    #!/usr/bin/env python3

    import errno
    import os
    import pty
    import sys
    from select import select
    from subprocess import Popen

    masters, slaves = zip(pty.openpty(), pty.openpty())
    with Popen([sys.executable, ‘-c’, r’‘’import sys, time
    print(‘stdout’, 1) # no explicit flush
    time.sleep(.5)
    print(‘stderr’, 2, file=sys.stderr)
    time.sleep(.5)
    print(‘stdout’, 3)
    time.sleep(.5)
    print(‘stderr’, 4, file=sys.stderr)
    ‘’‘],
    stdin=slaves[0], stdout=slaves[0], stderr=slaves[1]):
    for fd in slaves:
    os.close(fd) # no input
    readable = {
    masters[0]: sys.stdout.buffer, # log separately
    masters[1]: sys.stderr.buffer,
    }
    while readable:
    for fd in select(readable, [], [])[0]:
    try:
    data = os.read(fd, 1024) # read available
    except OSError as e:
    if e.errno != errno.EIO:
    raise #XXX cleanup
    del readable[fd] # EIO means EOF on some systems
    else:
    if not data: # EOF
    del readable[fd]
    else:
    readable[fd].write(data)
    readable[fd].flush()
    for fd in masters:
    os.close(fd)

我不知道

pty
对stdout,stderr使用不同的s有什么副作用。您可以尝试在您的情况下
stderr=PIPE
使用一个pty是否足够,例如,设置并使用
p.stderr.fileno()
代替
masters[1]
。来源中的评论
sh
表明,如果
stderrnot in {STDOUT,pipe}



欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5649537.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存