当前位置: 首页 > 知识库问答 >
问题:

如何使用Popen同时写入stdout和日志文件?

翟淮晨
2023-03-14

我正在使用Popen调用一个外壳脚本,它连续地将其stdout和stderr写入日志文件。有没有办法同时连续输出日志文件(到屏幕),或者让外壳脚本同时写入日志文件和stdout?

我主要想在Python中做这样的事情:

cat file 2>&1 | tee -a logfile #"cat file" will be replaced with some script

同样,这将stderr/stdout管道连接到tee,tee将其写入stdout和我的日志文件。

我知道如何用Python将stdout和stderr写入日志文件。我被困的地方是如何将这些复制回屏幕:

subprocess.Popen("cat file", shell=True, stdout=logfile, stderr=logfile)

当然,我可以这样做,但是没有tee和shell文件描述符重定向,有什么方法可以做到这一点吗

subprocess.Popen("cat file 2>&1 | tee -a logfile", shell=True)

共有3个答案

萧业
2023-03-14

为交互式应用程序逐字节写入终端

此方法立即写入它到达stdout的任何字节,这更密切地模拟了te的行为,尤其是对于交互式应用程序。

main.py

#!/usr/bin/env python3
import os
import subprocess
import sys
with subprocess.Popen(sys.argv[1:], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as proc, \
        open('logfile.txt', 'bw') as logfile:
    while True:
        byte = proc.stdout.read(1)
        if byte:
            sys.stdout.buffer.write(byte)
            sys.stdout.flush()
            logfile.write(byte)
            # logfile.flush()
        else:
            break
exit_status = proc.returncode

sleep.py

#!/usr/bin/env python3
import sys
import time
for i in range(10):
    print(i)
    sys.stdout.flush()
    time.sleep(1)

首先,我们可以进行非交互式的健全性检查:

./main.py ./sleep.py

我们看到它实时计数到标准输出。

接下来,对于交互式测试,您可以运行:

./main.py bash

然后,您键入的字符会在您键入时立即显示在终端上,这对于交互式应用程序非常重要。这是您跑步时发生的情况:

bash | tee logfile.txt

此外,如果希望输出立即显示在ouptut文件上,还可以添加:

logfile.flush()

但是tee不能做到这一点,我担心这会影响性能。您可以使用以下工具轻松测试这一点:

tail -f logfile.txt

相关问题:子进程命令的实时输出

在Ubuntu 18.04、Python 3.6.7上测试。

汪德寿
2023-03-14

模拟:subprocess.call("命令2

#!/usr/bin/env python2
from subprocess import Popen, PIPE, STDOUT

p = Popen("command", stdout=PIPE, stderr=STDOUT, bufsize=1)
with p.stdout, open('logfile', 'ab') as file:
    for line in iter(p.stdout.readline, b''):
        print line,  #NOTE: the comma prevents duplicate newlines (softspace hack)
        file.write(line)
p.wait()

要修复可能的缓冲问题(如果输出延迟),请参阅Python中的链接:从subprocess.communicate()读取流输入。

这是Python 3版本:

#!/usr/bin/env python3
import sys
from subprocess import Popen, PIPE, STDOUT

with Popen("command", stdout=PIPE, stderr=STDOUT, bufsize=1) as p, \
     open('logfile', 'ab') as file:
    for line in p.stdout: # b'\n'-separated lines
        sys.stdout.buffer.write(line) # pass bytes as is
        file.write(line)

司马高昂
2023-03-14

您可以使用管道从程序的标准输出读取数据,并将其写入您想要的所有位置:

import sys
import subprocess

logfile = open('logfile', 'w')
proc=subprocess.Popen(['cat', 'file'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
    sys.stdout.write(line)
    logfile.write(line)
proc.wait()

更新

在python 3中,universal\u newlines参数控制管道的使用方式。如果False,管道读取返回对象,可能需要解码(例如,行。解码('utf-8'))以获取字符串。如果为True,python将为您解码

在3.3版中更改:当universal_newlines为True时,类使用编码locale.getpreferredencoding(False)而不是locale.getpreferredencoding()。有关此更改的更多信息,请参阅io. TextIOWrapper类。

 类似资料:
  • 问题内容: 此代码是否同时写入日志文件和控制台? 问题答案: 不,它不会同时写入两者。只会写入控制台。关于原始代码的简短说明。我想您在某处定义,但是代码仍然不正确。您需要在语句中使用引号,例如: 因为我认为您是要附加到文件中。否则,您的代码将抛出一个因为未定义的变量。 但是,正如其他人所说,您应该强烈考虑使用日志记录模块。这是一个如何同时写入控制台和日志文件的简单示例。该代码部分源自此处和此处:

  • 我决定使用slf4j而不是Java自己的日志记录。我已经成功地使用SLF4J登录到控制台。但我不知道如何将其写入日志文件。日志文件将帮助我们收集运行时可能出现的错误。 我通过这样做来实现slf4j, 私有静态最终org.slf4j.LOGGER LOGGER=org.slf4j.loggerfactory.getlogger(class1.class); PropertyConfigurator.

  • 问题内容: 我遇到一种情况,我想将我创建的所有日志写入文本文件。 我们正在使用java.util.logging.Logger API生成日志。 我试过了: 但是仍然只能在控制台上获取我的日志。 问题答案: 试试这个样本。这个对我有用。 在MyLogFile.log产生输出 编辑: 要删除控制台处理程序,请使用 因为ConsoleHandler已向父记录器注册,所有记录器都源自该记录器。

  • 问题内容: 我正在尝试使用Go写入日志文件。 我尝试了几种方法,但都失败了。这是我尝试过的: 日志文件被创建,但是没有任何打印或附加到该文件。为什么? 问题答案: 过去的工作方式一定不同,但这对我有用: 基于Go文档,不能用于,因为它会打开文件“供阅读:” 打开命名文件以供读取。如果成功,则可以使用返回文件上的方法进行读取;关联的文件描述符具有mode 。如果有错误,它将是类型。 编辑 检查后移至

  • 我在写构建脚本。我想记录正在进行的一切,但我也想在它运行的时候看到一切。做这件事的最佳做法是什么?

  • 问题内容: 如何使用Python中的日志记录模块写入文件?每当我尝试使用它时,它只会打印出消息。 问题答案: 一个使用而不是一个例子 按顺序,这五个部分执行以下操作: 设置输出文件() 将其设置为追加而不是覆盖() 确定输出消息的格式() 确定输出时间的格式() 并确定它将接受的最低消息级别()。