如何在subprocess.Popen(stdout = None)中更改stdout = None继承的内容?

时间:2014-08-19 18:26:09

标签: python subprocess

这是为什么?

>>> sys.stdout=open("/dev/null", "w")
>>> subprocess.Popen(["echo", "foobar"], stdout=None)
foobar

我原本以为输出没有出现,而是开始了。文档说stdout=None是从父级继承句柄。

Martijn说,sys.stdout的赋值不会改变继承的句柄。

然后是什么handle以及如何更改它,以便它由stdtout=None的子进程调用继承,并且父进程和子进程输出都转到同一个地方?

2 个答案:

答案 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实际上相同。