繁体   English   中英

在 python 中,如何检查 subprocess.Popen 对象的标准输出是否有任何要读取的内容?

[英]In python, How do I check the stdout from a subprocess.Popen object for anything to read?

在 python 中,如何检查 subprocess.Popen 对象的标准输出是否有任何要读取的内容? 我正在为一个有时连续运行数小时的工具编写一个包装器。 在子进程的标准输出上使用 .readline() 会严重降低脚本运行时间超过几分钟的速度。 如果有任何要阅读的内容,我需要一种更有效地检查标准输出的方法。 顺便说一下,这个特殊的工具一次只能写完整的行。 脚本是这样的:

    #!/usr/bin/python -u
    #thiswrap.py

    import sys, time
    from subprocess import *

    chldp = Popen(sys.argv[1], bufsize=0, stdout=PIPE, close_fds=True)
    chstdin,chstdout=chldp.stdin,chldp.stdout
    startnoti=False

    while not chldp.poll():
        rrl=chstdout.readline() # <--- this is where the problem is
        if rrl[-8:]=='REDACTED TEXT':
            sys.stdout.write(rrl[:-1]+'   \r')
            if not startnoti: startnoti=True
        else:
            if startnoti: sys.stdout.write('\n')
            sys.stdout.write(rrl)
            if startnoti: # REDACTED
            time.sleep(0.1)
        time.sleep(0.1)

有任何想法吗?

您需要将文件描述符设置为非阻塞,您可以使用fcntl执行此操作:

import sys, time, fcntl, os
from subprocess import *

chldp = Popen(sys.argv[1], bufsize=0, stdout=PIPE, close_fds=True)
chstdin, chstdout = chldp.stdin, chldp.stdout
fl = fcntl.fcntl(chstdout, fcntl.F_GETFL)
fcntl.fcntl(chstdout, fcntl.F_SETFL, fl | os.O_NONBLOCK)

while chldp.poll() is not None:
    try:
        rrl = chstdout.readline()
    except IOError:
        time.sleep(0.1)
        continue
    # use rrl

当没有可用数据时, readline()IOError

请注意,由于chldp.poll()在子childp.poll() is not None完成时可能返回0 ,因此您可能应该在while使用childp.poll() is not None而不是not childp.poll()

可悲的是,没有现成的方法来轮询条件“管道中有足够的数据与换行符,因此 readline() 将立即返回”。

如果您一次想要一行,并且不想阻塞,您可以:

通过类或生成器实现您自己的缓冲并通过它进行轮询,例如:

def linereader():
    data = ""
    while True:
        if poll(f.fd):
            data += f.read(100)
        lines = data.split("\n")
        data = lines[-1]
        for line in lines[:-1]:
            yield line

# use
for line in linereader():
    if line:
       print line
    else:
       time.sleep(...)

或者使用线程(留给读者作为练习,请注意,如果您从主线程以外的线程启动子进程,则旧版本的 python 错误)

第一条评论中提出的解决方案几乎是正确的。 您只需要将整数文件描述符作为第一个参数传递给fcntl.fcntl ,而不是 Python 文件对象。 取自另一个答案

这是要更改的代码:

chstdout = chldp.stdout
fd = chstdout.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM