subprocess.Popen communication()写入控制台,但不写入日志文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了subprocess.Popen communication()写入控制台,但不写入日志文件相关的知识,希望对你有一定的参考价值。

我在Python脚本中有以下行,它在原始脚本中运行单独的Python脚本:

subprocess.Popen("'/MyExternalPythonScript.py' " + theArgumentToPassToPythonScript, shell=True).communicate()

使用上面的行,在单独的Python文件中找到的任何print()语句都会出现在主Python脚本的控制台中。

但是,这些语句不会反映在脚本写入的.txt文件日志中。

有谁知道如何解决这个问题,以便.txt文件准确反映主Python脚本的真实控制台文本?


这是我用来将控制台保存为.txt文件的the method,实时:

import sys
class Logger(object):
    def __init__(self):
        self.terminal = sys.stdout
        self.log = open("/ScriptLog.txt", "w", 0)
    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)


sys.stdout = Logger()

我不一定依赖这种方法。我对能够实现我所详述的任何方法感兴趣。

答案

请记住,subprocess会生成一个新进程,并且不会真正与父进程通信(它们几乎是独立的实体)。尽管它的名称,communicate方法只是一种从父进程发送/接收数据到子进程的方式(例如,模拟用户在终端上输入内容)

为了知道输出的写入位置,子进程使用数字(文件标识符或文件号)。当子进程生成进程时,子进程只知道标准输出是O.S中标识的文件。作为7(说一个数字),但这就是它。子流程将独立地查询操作系统,例如“嘿!什么是文件号7?给我,我有东西要写在里面”。 (了解C fork的作用在这里非常有帮助)

基本上,衍生的子流程不理解你的Logger类。它只知道它必须将其内容写入文件:在OS中用数字唯一标识的文件,除非另有说明,否则该数字对应于标准输出的文件描述符(但在案例#中说明)如下图2所示,您可以根据需要进行更改)

所以你有几个“解决方案”......

  1. 克隆(tee)stdout到一个文件,所以当某些内容被写入stdout时,操作系统也将它写入你的文件(这实际上与Python不相关......它与操作系统有关): import os import tempfile import subprocess file_log = os.path.join(tempfile.gettempdir(), 'foo.txt') p = subprocess.Popen("python ./run_something.py | tee %s" % file_log, shell=True) p.wait()
  2. 选择是否使用每个的fileno()函数写入终端OR或文件。例如,只写入文件: import os import tempfile import subprocess file_log = os.path.join(tempfile.gettempdir(), 'foo.txt') with open(file_log, 'w') as f: p = subprocess.Popen("python ./run_something.py", shell=True, stdout=f.fileno()) p.wait()
  3. 我个人觉得“更安全”(我觉得不能轻易覆盖sys.stdout):只需让命令运行并将其输出存储到变量中并稍后(在父进程中)获取它: import os import tempfile import subprocess p = subprocess.Popen("python ./run_something.py", shell=True, stdout=subprocess.PIPE) p.wait() contents = p.stdout.read() # Whatever the output of Subprocess was is now stored in 'contents' # Let's write it to file: file_log = os.path.join(tempfile.gettempdir(), 'foo.txt') with open(file_log, 'w') as f: f.write(contents) 这样,您还可以在代码中的某处执行print(contents),以将子进程“说”输出到终端。

例如,脚本“./run_something.py”就是这样的:

print("Foo1")
print("Foo2")
print("Foo3")
另一答案

你真的需要subprocess.Popencommunicate()方法吗?看起来你只想要输出。这就是subprocess.check_output()的用途。

如果您使用它,您可以使用内置的logging模块“tee” - 输出流到多个目的地。

import logging
import subprocess
import sys

EXTERNAL_SCRIPT_PATH = '/path/to/talker.py'
LOG_FILE_PATH = '/path/to/debug.log'

logger = logging.getLogger('')
logger.setLevel(logging.INFO)

# Log to screen
console_logger = logging.StreamHandler(sys.stdout)
logger.addHandler(console_logger)

# Log to file
file_logger = logging.FileHandler(LOG_FILE_PATH)
logger.addHandler(file_logger)

# Driver script output
logger.info('Calling external script')

# External script output
logger.info(
    subprocess.check_output(EXTERNAL_SCRIPT_PATH, shell=True)
)

# More driver script output
logger.info('Finished calling external script')

一如既往,小心shell=True。如果您可以将呼叫写为subprocess.check_output(['/path/to/script.py', 'arg1', 'arg2']),请执行此操作!

以上是关于subprocess.Popen communication()写入控制台,但不写入日志文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用子进程 Popen.communicate() 方法?

管道输出subprocess.Popen到文件

子进程失效,`communicate()` 挂起

如何使用Python中的subprocess.Popen返回编码值?

我啥时候应该在子进程中使用`wait`而不是`communicate`?

Python 在线程中调用 pipe.communicate()