也许在以太坊里有人可以帮助我。(我在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()
EOF
while
我可以替换为read(),read(int)但是打印输出失真,在读取字符的末尾切断。我可以readline()代替它,但是当同时发生很多输出和错误时,打印输出会因输出和错误的交替出现而失真。
read(int)
readline()
也许有一个read-until-end-of-buffer()我不知道的变体?还是可以实施?
read-until-end-of-buffer()
也许最好按照另一个帖子的答案中的sys.stdout建议实现一个包装器?但是,我只想在此函数中使用包装器。
sys.stdout
社区还有其他想法吗?
感谢您的帮助!:)
编辑 :解决方案确实应该是跨平台的,但是如果您没有想法,请与他人分享以保持头脑风暴。
使用来使管道成为非阻塞状态fcntl.fcntl,并使用select.select来等待数据在任一管道中变为可用。例如:
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平台上可用。
fcntl
如果您需要它在不使用Cygwin的Windows上运行,那是可行的,但难度要大得多。您必须:
SetNamedPipeHandleState
PIPE_NOWAIT
WaitForMultipleObjects
select
ReadFile