这是为什么?
>>> sys.stdout=open("/dev/null", "w")
>>> subprocess.Popen(["echo", "foobar"], stdout=None)
foobar
我原本以为输出没有出现,而是开始了。文档说stdout=None
是从父级继承句柄。
Martijn说,sys.stdout
的赋值不会改变继承的句柄。
然后是什么handle
以及如何更改它,以便它由stdtout=None
的子进程调用继承,并且父进程和子进程输出都转到同一个地方?
答案 0 :(得分:3)
不,父进程句柄不转到/dev/null
。您没有更改进程句柄,只反弹Python sys.stdout
以指向新的文件对象。
顺便说一下,你仍然可以在sys.stdout
下找到原始的sys.__stdout__
对象,而且该对象实际上只是将Python字符串对象转换为字符以写入实际文件句柄的包装器下进行。
实际进程句柄是文件描述符编号,操作系统指示该进程的文件描述符。要从Python更改该句柄,您必须使用os.close()
和os.dup2()
调用来执行一些文件描述符:
import os
def freopen(filename, mode, fobj):
new = open(filename, mode)
newfd = new.fileno()
targetfd = fobj.fileno()
os.close(targetfd)
os.dup2(newfd, targetfd)
然后使用:
freopen('/dev/null', 'w', sys.stdout)
更容易将文件对象直接传递给subprocess
但是:
with open("/dev/null", "w") as devnull:
subprocess.Popen(["echo", "foobar"], stdout=devnull)
答案 1 :(得分:1)
sys.stdout
只是一个python对象;真正的魔法发生在文件描述符/描述级别,可以使用os
模块
理论上,您可以通过执行以下操作将文件描述符1定向到另一个文件:
sys.stdout.flush()
fd = os.open("/dev/null", "w")
sys.stdout = os.fdopen(fd, "w")
os.dup2(fd, 1)
os.close(fd)
虽然我不保证在所有情况下都能做到你想做的事情;更好的是给subprocess.Popen
一个新的stdout Python文件,例如:
null = open("/dev/null", "w")
subprocess.Popen(..., stdout=null)
null.close()
None
的默认stdout
实际上代表继承(不对打开的文件做任何事情)。由于sys.stdout.fileno()
通常是1
(除非发生了一些非常可疑的事情),因此这通常与stdout=sys.stdout
实际上相同。