python子进程赢得';t像终端那样交错stderr和stdout
测试程序python子进程赢得';t像终端那样交错stderr和stdout,python,python-3.x,subprocess,Python,Python 3.x,Subprocess,测试程序 #/usr/bin/env蟒蛇3 导入系统 计数=0 sys.stderr.write('stderr,订单%d\n“%count”) 计数+=1 sys.stdout.write('stdout,订单%d\n“%count”) 计数+=1 sys.stderr.write('stderr,订单%d\n“%count”) 计数+=1 sys.stdout.write('stdout,订单%d\n“%count”) 通过终端调用时,预期输出为 stderr, order 0 stdou
#/usr/bin/env蟒蛇3
导入系统
计数=0
sys.stderr.write('stderr,订单%d\n“%count”)
计数+=1
sys.stdout.write('stdout,订单%d\n“%count”)
计数+=1
sys.stderr.write('stderr,订单%d\n“%count”)
计数+=1
sys.stdout.write('stdout,订单%d\n“%count”)
通过终端调用时,预期输出为
stderr, order 0
stdout, order 1
stderr, order 2
stdout, order 3
在交互式shell中,当我将stdout
重定向到管道时,输出顺序与上面的输出不同,在上面的输出中,Popen将stderr
分组并将它们全部写入,然后对stdout
执行相同的操作,而不是交错stdout和stderr
In [29]: a = sp.run(['./test.py'], stderr=sp.STDOUT)
stderr, order 0
stdout, order 1
stderr, order 2
stdout, order 3
In [30]: a
Out[30]: CompletedProcess(args=['./test.py'], returncode=0)
In [33]: b = sp.Popen(['./test.py'], stderr=sp.STDOUT, stdout=sp.PIPE, encoding='utf-8')
In [34]: print(b.communicate()[0])
stderr, order 0
stderr, order 2
stdout, order 1
stdout, order 3
在C库(以及基于C的python)中,流的处理方式不同,这取决于它们是否连接到交互终端(或假装连接的东西)。对于tty
,stdout
是行缓冲的,否则它的块会被缓冲,并且只有在命中某个块边界时才会刷新到文件描述符。当您重定向到管道时,流不再是tty,块缓冲生效
解决方案是重新打开stdout
,指定您希望不考虑行缓冲(1)。在C级,stderr
始终是行缓冲的,但当我测试时,只是重新打开stdout
程序就好像stderr
是块缓冲的。我很惊讶。也许这是中间的io.TextIO
层或者其他一些奇怪的东西,但是我发现我需要修复这两个管道
即使stdout
和stderr
进入同一管道,但就执行的程序而言,它们是具有独立缓冲区的独立文件描述符。这就是为什么即使在块模式下,交错也不会在输出缓冲区中自然发生
#!/usr/bin/env python3
import sys
import os
# reopen stdout line buffered
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
# this surprises me, seems like we have to reopen stderr
# line buffered, but i thought it was line buffered anywy.
# perhaps its the intermediate python TextIO layer?
sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 1)
count = 0
sys.stderr.write('stderr, order %d\n' % count)
count += 1
sys.stdout.write('stdout, order %d\n' % count)
count += 1
sys.stderr.write('stderr, order %d\n' % count)
count += 1
sys.stdout.write('stdout, order %d\n' % count)