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

时间:2017-12-27 23:08:58

标签: python subprocess

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

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

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

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

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

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

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()

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

2 个答案:

答案 0 :(得分:1)

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

如果你使用它,你可以使用内置的logging模块来实现输出流到多个目的地。

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']),请执行此操作!

答案 1 :(得分:0)

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

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

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

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

  1. 克隆(fork)stdout到一个文件,所以当某些东西被写入stdout时,操作系统也会将它写入你的文件(这实际上与Python不相关......它与OS有关):

    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)输出子进程“所说的”到终端。

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

    print("Foo1")
    print("Foo2")
    print("Foo3")
    
相关问题