【问题标题】:Having a subprocess output redirected to a log file whose name is the pid of the subprocess将子进程输出重定向到名称为子进程 pid 的日志文件
【发布时间】:2016-01-22 16:32:17
【问题描述】:

假设我创建了一个subprocess

import subprocess
ps = subprocess.Popen(command, shell=True)

我希望将新进程的输出重定向到名为x.log 的文件中,其中x 是已创建进程的pid。

如何做到这一点?


我尝试在远程服务器上运行多个进程,每个进程都需要数天才能完成。我希望能够查看在创建它们的脚本完成运行后仍在运行的进程的进度,因此我需要它们在文件中的输出,并且能够了解哪个文件是由哪个 pid 生成的。


目前,我在创建进程之前绘制了一个随机数 r,将其输出重定向到 r.log 并维护 pid 与其输出文件之间的映射。这似乎很愚蠢,因为我只需要让进程将其输出重定向到一个名为进程 pid 的文件。

【问题讨论】:

    标签: python multithreading logging multiprocessing pid


    【解决方案1】:

    subprocess.Popenstdoutstderr 参数允许您 将标准输出重定向到不同类型的流。

    标准输入标准输出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。解决此问题的一种方法是使用 bashexec 运行命令。

    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 用于正确处理生成的进程的终止。

    【讨论】:

    • 是的,我知道 stdout 参数,但是,我不知道如何使用它将输出重定向到名称为进程 pid 的文件中...... pid 似乎只是在执行 Popen 命令后可用,此时我不确定如何使子进程重定向其输出。
    • @RB 如果您绝对需要 pid,您将无法使用 stdout 参数。 preexec_fn 的第二个解决方案怎么样,它是否适合您的流程?
    • 您可以在创建子进程时尝试暂停子进程,获取其 ID,将其输出重定向到文件,然后从父进程发送信号以恢复它。我快速尝试了一下,但无法做到这一点......
    • 我不确定我是否理解如何使用这个preexec_fn。子进程是编译后的代码,我无法更改,如何让它检查它的pid?
    • 这几乎可以工作:)。它在运行命令的 shell 的 pid 下生成它。
    【解决方案2】:

    尝试在您的 Python 代码中使用“currentSubProcess = subprocess.check_output("your Command")”。 这样“currentSubProcess”将包含您的子流程的输出,您可以将其写入日志文件中。

    【讨论】:

    • 感谢您的回答,但我不确定这是否有帮助。我尝试在远程服务器上运行多个进程,每个进程都需要几天才能完成。我希望能够查看在创建它们的脚本完成运行后仍在运行的进程的进度,因此我需要它们的文件输出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-11
    • 2011-04-20
    • 2015-04-04
    • 1970-01-01
    • 2012-07-04
    • 1970-01-01
    • 2015-01-01
    相关资源
    最近更新 更多