registcn 发表于 2014-06-04 23:56

popen的子进程无法继承父进程的重定向信息?


import ConfigParser
import sys
import os,sys
from subprocess import *

sys.stdout = open('/dev/null', 'w')
print "aaa"

p=Popen(['echo', 'bbb'])
p.wait()

_____________________________

运行结果,屏幕上不再有aaa ,但是有bbb。这岂不是子进程未继承父进程的重定向属性吗?怎么解决?

bikong0411 发表于 2014-06-05 09:44

import subprocess
p=Popen(['echo', 'bbb'], stdout=suprocess.PIPE)
print p.stdout.readlines()

baopbird2005 发表于 2014-06-05 10:38

楼上正解。:mrgreen:

registcn 发表于 2014-06-05 13:50

这样确实可以实现,但我想问的是,父进程已经把stdout改了——子进程的stdout应该也重定向了,那,为什么子进程 还 需要管道中明确指明stdout呢?

回复 2# bikong0411


   

timespace 发表于 2014-06-05 15:20

本帖最后由 timespace 于 2014-06-05 15:23 编辑

sys.stdin
sys.stdout
sys.stderr
File objects corresponding to the interpreter’s standard input, output and error streams. stdin is used for all interpreter input except for scripts but including calls to input() and raw_input(). stdout is used for the output of print and expression statements and for the prompts of input() and raw_input(). The interpreter’s own prompts and (almost all of) its error messages go to stderr. stdout and stderr needn’t be built-in file objects: any object is acceptable as long as it has a write() method that takes a string argument. (Changing these objects doesn’t affect the standard I/O streams of processes executed by os.popen(), os.system() or the exec*() family of functions in the os module.)
文档写的很清楚,修改sys.std*并不是进程0/1/2重定向。如果只是想让子进程0/1/2重定向,用subprocess就可以了;如果熟悉重定向原理,用os.dup/os.dup2,这是其他module重定向实现的基础。

timespace 发表于 2014-06-05 16:30

底层os实现:Python 2.7.5 (default, Mar9 2014, 22:15:05)
on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> old_out = os.dup(1)
>>> new_out = os.open(os.devnull, os.O_RDWR)
>>> old_out, new_out
(3, 4)
>>> print 'hi', os.getpid()
hi 835
>>> os.system('echo $')
839
0
>>> os.dup2(new_out, 1) # 将标准输出重定向到/dev/null
>>> print 'hi', os.getpid()
>>> os.system('echo $')
>>> os.dup2(old_out, 1) # 将标准输出重定向到默认终端
>>> print 'hi', os.getpid()
hi 835
>>> os.system('echo $')
851
0
高层sys和subprocess实现:Python 2.7.5 (default, Mar9 2014, 22:15:05)
on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, sys, subprocess
>>> old_out = sys.stdout
>>> new_out = open(os.devnull, 'wb')
>>> print 'hi', os.getpid()
hi 878
>>> subprocess.call('echo $', shell=True)
881
0
>>> sys.stdout = new_out
>>> print 'hi', os.getpid()
>>> subprocess.call('echo $', stdout=new_out, shell=True)
>>> sys.stdout = old_out
>>> print 'hi', os.getpid()
hi 878
>>> subprocess.call('echo $', shell=True)
886
0
显然前者是系统调用的直译,后者更符合Python风格,推荐后者。

timespace 发表于 2014-06-05 16:33

擦,CU编辑器把源码的两个$自动合并为一个$,copy上面代码的人自动脑补吧。。。

修杰_JIANG 发表于 2014-06-05 17:58

subprocessfork 一个进程 调用了 os.execvpe() 来处理command想要输出重定向 用os.dup2, subprocess 已经做了这样的事情
help(subprocess.Popen.__init__)

Help on method __init__ in module subprocess:

__init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0) unbound subprocess.Popen method
    Create new Popen instance.

registcn 发表于 2014-06-06 09:54

给力,搞定!回复 5# timespace


   

registcn 发表于 2014-06-06 10:00

init中的std*=none底层就是用dup实现的?如果是这样,那none代表继承父进程属性,这和我贴的例子不相符(实际测试发现未继承)啊?

回复 8# 修杰_JIANG


   
页: [1] 2
查看完整版本: popen的子进程无法继承父进程的重定向信息?