记录并压缩 subprocess.call 的输出

Log and compress the output of subprocess.call

我想将 subprocess.call(...) 的输出重定向到 xz 或 bzip2 压缩文件。

我试过了:

with lzma.open(log_path, "x") as log_file:
    subprocess.call(command, stdout=log_file, stderr=log_file)

但生成的文件不是有效的 XZ 压缩文件:

$ xzcat logfile.xz
xzcat : logfile.xz: Format de fichier inconnu

(在法语中,意思是 "unknown file format")。

当我只使用 cat 时,文件显示正确,最后有一些奇怪的数据(脚本中启动的命令是 rsync):

& cat logfile.xz
sending incremental file list
prog/testfile

sent 531.80K bytes  received 2.71K bytes  1.07M bytes/sec
total size is 14.21G  speedup is 26,588.26
�7zXZ�ִF�D!��}YZ

logfile.xz 似乎是一个半有效的 XZ 存档文件,其中填充了未压缩的数据。我做错了什么?

PS :当我这样做时它会起作用 :

output = subprocess.check_output(command)
log_file.write(output)

...但是鉴于该命令需要很长时间(它是一个备份脚本),我希望能够在结束之前看到日志(带有xzcat),以了解rsync是什么正在做。

重定向甚至发生在子进程执行之前的文件描述符级别:没有父代码(与子进程的 stdout/stderr 相关)在那之后 运行(Python 代码来自 lzma 模块不是 运行).

要即时压缩以便您可以在子进程仍在 运行ning 时看到输出,您可以将其输出重定向到 xz 实用程序:

#!/usr/bin/env python3
import subprocess

with open('logfile.xz', 'xb', 0) as log_file:
    subprocess.call("command | xz -kezc -", shell=True,
                    stdout=log_file, stderr=subprocess.STDOUT)

注意:使用的是普通的open(),不是lzma.open():压缩是在xz子进程中完成的。


如果你想在纯 Python 代码中压缩,那么你必须通过管道传输数据 python:

#!/usr/bin/env python3
import lzma
from subprocess import Popen, PIPE, STDOUT
from shutil import copyfileobj

with lzma.open('logfile.xz', 'xb') as log_file, \
     Popen('command', stdout=PIPE, stderr=STDOUT) as process:
    copyfileobj(process.stdout, log_file)

注:使用lzma.open()