【问题标题】:Python script differs output between terminal and redirection to a filePython脚本在终端和重定向到文件之间的输出不同
【发布时间】:2015-01-15 15:58:39
【问题描述】:

我正在编写一个带有各种 subprocess.call 的大型 python 脚本来执行系统中可用的命令,但我遇到了一个问题,因为如果将其打印到终端或重定向到文件,输出会有所不同。

为了重现问题,这是脚本的一小部分:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from subprocess import call

print "Hello at first"
call(["rsync", "-aHvz", "root@server1:/tmp/a", '.'])
print "Hello at the end"

从终端执行它以正确的顺序返回,print + rsync + print:

$ python keepconf.py
Hello at the first
receiving incremental file list

sent 12 bytes  received 123 bytes  270.00 bytes/sec
total size is 55858143  speedup is 413764.02
Hello at the end

执行相同的操作,但将输出重定向到文件:

$ python keepconf.py  > /tmp/output
$ cat /tmp/output
receiving incremental file list

sent 12 bytes  received 123 bytes  270.00 bytes/sec
total size is 55858143  speedup is 413764.02
Hello at the first
Hello at the end

现在的顺序是 rsync + print + print。为什么会出现这种行为?

【问题讨论】:

  • 在打印后使用 sys.stdout.flush() ?

标签: python output stdout


【解决方案1】:

终端的输出(或更准确地说,tty)通常在 Python 中以 行缓冲模式 打开。当你使用管道时,Python 会使用一个不同的缓冲区,它的大小是固定的。

这意味着当您使用换行符写入文本时,缓冲区会在打印到终端时自动刷新,但对于管道,只有在缓冲区已满或强制刷新时才会刷新(例如当Python 脚本退出)。

换句话说,当写入终端时,第一行打印在rsync 命令运行之前被刷新到终端。重定向到管道时,文本保存在缓冲区中,运行rsync 命令输出(在刷新时写入管道,至少在最后一次但可能更频繁),然后再写入缓冲区,当 Python 存在时,该缓冲区会刷新到管道中。

您可以手动强制刷新:

import sys

# ....
print "Hello at first"
sys.stdout.flush()
call(["rsync", "-aHvz", "root@server1:/tmp/a", '.'])
print "Hello at the end"
sys.stdout.flush()

【讨论】:

  • 点赞。更正:sys.stdout(和子进程写入的 C 标准输出流)如果引用 tty(常见于基于 stdio 的程序,例如 python2),则可能是行缓冲的。终端编辑模式(raw、line)与这里无关。
  • @J.F.Sebastian:合格;我习惯性地把它简称为终端,但实际使用过物理终端,你说的不够精确是对的。
  • 没有。我的意思是sys.stdout Python 对象,C stdout (FILE*)(程序属性--内部)不同于终端 (stty 可能会更改其参数)。后者存在于程序之前/期间/之后(外部)。缓冲区在进程内部。
  • @J.F.Sebastian:对,我这里说的是Python进程中的缓冲区。
猜你喜欢
  • 2017-12-01
  • 1970-01-01
  • 2022-09-23
  • 2012-11-15
  • 2017-08-31
  • 2017-03-14
  • 1970-01-01
  • 2014-10-24
  • 2018-01-11
相关资源
最近更新 更多