【问题标题】:Log and compress the output of subprocess.call记录并压缩 subprocess.call 的输出
【发布时间】:2015-12-06 03:03:54
【问题描述】:

我想将 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在做什么。

【问题讨论】:

    标签: python python-3.x compression subprocess


    【解决方案1】:

    重定向发生在子级甚至执行之前的文件描述符级别:此后没有运行父代码(与子级的 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()

    【讨论】:

    • 谢谢!这个“没有父代码”的事情很奇怪。我选择使用纯 Python。
    • @YdobEmos 没什么奇怪的,这就是管道和重定向在 shell 中的工作方式:command | another >output.txt 2>&1
    • 我觉得它不直观,我希望我在 LZMA 文件中发送的数据在写入之前会被压缩。 (我说的是你的“没有父代码(与孩子的 stdout/stderr 相关)在那之后运行(来自 lzma 模块的 Python 代码没有运行)”句子)。
    • 是的,我说的是同一件事。只有log_file.fileno() 结果被使用——文件描述符(一个整数)。很明显,如果您知道how the redirection works (dup2()),则不会发生压缩(不运行 python 代码)。它不是特定于 Python 的。使用 POSIX 接口重新实现 Popen 可能具有教育意义
    猜你喜欢
    • 2015-06-11
    • 2016-03-17
    • 2019-11-02
    • 1970-01-01
    • 2021-07-19
    • 2015-10-14
    • 2021-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多