记录并压缩subprocess.call

时间:2015-12-06 03:03:54

标签: python python-3.x compression subprocess

我想将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

(用法语表示"未知文件格式")。

当我只使用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是什么正在做。

1 个答案:

答案 0 :(得分:2)

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

要动态压缩以便在子进程仍在运行时可以看到输出,您可以将其输出重定向到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()