subprocess.Popen 的stdout 和 stderr 参数允许您
将标准输出重定向到不同类型的流。
标准输入,标准输出
和 stderr 指定执行程序的标准输入,标准
输出和标准错误文件句柄,分别。 有效值为
PIPE,一个现有的文件描述符(一个正整数),一个现有的
文件对象和无。 [...] 子文件句柄将继承自
父母。此外,stderr 可以是 STDOUT,这表明
来自子进程的 stderr 数据应该被捕获到相同的
文件句柄与标准输出相同。
您可能想尝试将输出重定向到此处的文件,但您没有子进程的 pid 来正确命名输出文件。
如果您的脚本在 Unix 上运行,您还可以尝试将可调用对象传递给 Popen 的参数 preexec_fn,这将用文件处理程序替换默认输出流。通过这个方案,你实际上可以通过os.getpid获取当前进程的pid。
如果 preexec_fn 设置为可调用对象,则该对象将被调用
在子进程执行之前的子进程中。 (仅限 Unix)
我用preexec_fn 解决方案做了一些测试,只是替换sys.stdout 不起作用。但doing it at the file descriptor level 似乎有效。
def redirect_output():
import sys, os
# The opened file needs to stay alive
redirect_output._file = open('{}.log'.format(os.getpid()), 'w')
os.dup2(redirect_output._file.fileno(), sys.stdout.fileno())
sub = subprocess.Popen(['ls'], preexec_fn=redirect_output)
当然,这是一个简单的示例,可能需要进行一些改进。
上面的例子在shell = False 时似乎工作正常,但在shell = True 的情况下,你得到了shell 的pid。解决此问题的一种方法是使用 bash 和 exec 运行命令。
command = 'python -c "import os; print \'\\\'\'process: \'\\\'\', os.getpid()"'
sub = subprocess.Popen(["bash -c 'exec {} > $$.log'".format(command)],
shell = True,
preexec_fn = os.setsid
)
print 'Shell: ', sub.pid
这里os.setsid 用于正确处理生成的进程的终止。