读取日志文件中的最后一条错误消息

Reading last error message in log file

在Python 2.7中,我在某个循环中有以下代码

file = open("log.txt", 'a+')
last_position = file.tell()
subprocess.Popen(["os_command_producing_error"], stderr = file)
file.seek(last_position)
error = file.read()
print(error) # example of some action with the error

目的是让 stderr 刚刚给出的错误得到打印,而 file 保留整个记录。

我是 Python 的初学者,我不清楚 stderr = file 中发生了什么。

我的问题是 error 一直是空的,尽管 file 中不断记录错误。

有人可以解释为什么吗?

我试过在 subprocess 行之后再次添加关闭和打开文件,或者 file.flush()。但是还是一样的效果。

编辑: 下面答案中的代码对我来说很有意义,它似乎适用于 post 的作者。对我来说(在 Windows 中)它不起作用。它给出一个空 err 和一个空文件 log.txt。如果我 运行 它逐行(例如调试)它确实有效。如何理解和解决这个问题?

编辑: 我将 Popen 更改为 call,现在可以使用了。我想 call 等待 subprocess 完成才能继续脚本。

尝试以下代码:

file = open("log.txt", 'a+')
sys.stderr = file
last_position = file.tell()
try:
    subprocess.call(["os_command_producing_error"])
except:
    file.close()
    err_file = open("log.txt", 'r')
    err_file.seek(last_position)
    err = err_file.read()
    print err
    err_file.close()

sys.stderr 映射标准错误消息,如 sys.stdout(映射标准输出)和 sys.stdin(映射标准输入)。

这会将标准错误映射到 file。所以所有的标准错误都将写入文件 log.txt.

error 为空,因为您在进程有机会向文件写入任何内容之前读取得太早。 Popen() 启动一个新进程;它不会等待它完成。

call() 等同于等待子进程退出的 Popen().wait() 这就是为什么在这种情况下你应该看到非空 error (如果子进程确实写stderr).

的任何内容
#!/usr/bin/env python
import subprocess

with open("log.txt", 'a+') as file:
   subprocess.check_call(["os_command_producing_error"], stderr=file)
   error = file.read()
print(error)

你应该小心mixing buffered (.read()) and unbuffered I/O (subprocess)

这里不需要外部文件,读取错误:

#!/usr/bin/env python
import subprocess

error = subprocess.check_output(["os_command_producing_error"],
                                stderr=subprocess.STDOUT)
print(error)

它合并了 stderr 和 stdout 以及 returns 输出。

如果您不想捕获标准输出然后只获取标准错误,您可以使用 Popen.communicate():

#!/usr/bin/env python
import subprocess

p = subprocess.Popen(["os_command_producing_error"], stderr=subprocess.PIPE)
error = p.communicate()[1]
print(error)

您可以捕获 stderr 并将其附加到文件中:

#!/usr/bin/env python
import subprocess

error = bytearray()
p = subprocess.Popen(["os_command_producing_error"],
                     stderr=subprocess.PIPE, bufsize=1)
with p.stderr as pipe, open('log.txt', 'ab') as file:
    for line in iter(pipe.readline, b''):
        error += line
        file.write(line)
p.wait()
print(error)

参见 Python: read streaming input from subprocess.communicate()