将subprocess.Popen的输出重定向到文件
我需要启动一些运行时间较长的进程,使用的是 subprocess.Popen
。我希望每个进程的 stdout
(标准输出)和 stderr
(标准错误)能够自动分别写入不同的日志文件。每个进程会同时运行几分钟,我想为每个进程准备两个日志文件(一个是 stdout
,一个是 stderr
),并且在进程运行时实时写入这些文件。
我是否需要在一个循环中不断调用 p.communicate()
来更新每个日志文件,还是有其他方法可以让原始的 Popen
命令自动将 stdout
和 stderr
流式传输到打开的文件中呢?
4 个回答
3
我同时在运行两个子进程,并把它们的输出都保存到一个日志文件里。我还设置了一个超时,以防子进程卡住。当输出变得太大时,超时总是会触发,这样两个子进程的标准输出都不会被保存到日志文件里。上面Alex提出的解决方案并没有解决这个问题。
# Currently open log file.
log = None
# If we send stdout to subprocess.PIPE, the tests with lots of output fill up the pipe and
# make the script hang. So, write the subprocess's stdout directly to the log file.
def run(cmd, logfile):
#print os.getcwd()
#print ("Running test: %s" % cmd)
global log
p = subprocess.Popen(cmd, shell=True, universal_newlines = True, stderr=subprocess.STDOUT, stdout=logfile)
log = logfile
return p
# To make a subprocess capable of timing out
class Alarm(Exception):
pass
def alarm_handler(signum, frame):
log.flush()
raise Alarm
####
## This function runs a given command with the given flags, and records the
## results in a log file.
####
def runTest(cmd_path, flags, name):
log = open(name, 'w')
print >> log, "header"
log.flush()
cmd1_ret = run(cmd_path + "command1 " + flags, log)
log.flush()
cmd2_ret = run(cmd_path + "command2", log)
#log.flush()
sys.stdout.flush()
start_timer = time.time() # time how long this took to finish
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(5) #seconds
try:
cmd1_ret.communicate()
except Alarm:
print "myScript.py: Oops, taking too long!"
kill_string = ("kill -9 %d" % cmd1_ret.pid)
os.system(kill_string)
kill_string = ("kill -9 %d" % cmd2_ret.pid)
os.system(kill_string)
#sys.exit()
end_timer = time.time()
print >> log, "closing message"
log.close()
94
你可以把 stdout
和 stderr
作为参数传递给 Popen()
这个函数。
subprocess.Popen(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)
比如说:
>>> import subprocess
>>> with open("stdout.txt","wb") as out, open("stderr.txt","wb") as err:
... subprocess.Popen("ls",stdout=out,stderr=err)
...
<subprocess.Popen object at 0xa3519ec>
>>>
42
根据文档,
stdin、stdout和stderr分别代表程序的标准输入、标准输出和标准错误的文件句柄。有效的值可以是PIPE、一个已经存在的文件描述符(正整数)、一个已经存在的文件对象,或者是None。
所以,只需要把打开用于写入的文件对象作为命名参数 stdout=
和 stderr=
传进去就可以了!