Python脚本在终端输出和文件重定向之间有所不同

Python脚本在终端输出和文件重定向之间有所不同,python,output,stdout,Python,Output,Stdout,我正在编写一个包含各种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",

我正在编写一个包含各种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。为什么会出现这种行为?

对于终端的输出,或者更准确地说,在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()

对于终端的输出,或者更准确地说,在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.flush?打印后使用sys.stdout.flush?向上投票。更正:sys.stdout和C stdout流,如果子进程写入引用了基于stdio的程序(如python2)的tty公共,则子进程写入可能会被行缓冲。终端编辑模式原始,此处的行不相关。@J.F.Sebastian:合格;我习惯性地把它简称为终端,但实际上使用了物理终端,你是对的,这不够精确。我的意思是sys.stdout Python对象、C stdout FILE*程序属性-内部与终端stty不同,可能会更改其参数。后者存在于程序外部之前/期间/之后。缓冲区在进程内部。@J.F.Sebastian:对,我在这里谈论的是Python进程中的缓冲区。upvote。更正:sys.stdout和C stdout流,如果子进程写入引用了基于stdio的程序(如python2)的tty公共,则子进程写入可能会被行缓冲。终端编辑模式原始,此处的行不相关。@J.F.Sebastian:合格;我习惯性地把它简称为终端,但实际上使用了物理终端,你是对的,这不够精确。我的意思是sys.stdout Python对象、C stdout FILE*程序属性-内部与终端stty不同,可能会更改其参数。后者存在于程序外部之前/期间/之后。缓冲区在进程内部。@J.F.Sebastian:好的,我在这里谈论的是Python进程中的缓冲区。