我在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()
我不一定依赖这种方法。我对能够实现我所详述的任何方法感兴趣。
答案 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中进行更改
所以你有几个“解决方案”......
克隆(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()
选择是否使用每个的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()
我个人觉得“更安全”(我觉得不能轻易覆盖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")