2015-01-15 10 views
1

我正在寫一個大的python腳本和各種subprocess.call來執行系統中可用的命令,並且我遇到了一個問題,因爲如果它輸出到終端或者是否被重定向到文件。Python腳本在終端和重定向到一個文件之間的輸出不同

爲了重現該問題,這是劇本的一小部分:

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

from subprocess import call 

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

從終端返回,在正確的順序,打印+ rsync的+打印執行它:

$ 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 + pri nt +打印。這是爲什麼?

+0

並與sys.stdout.flush()後,您的打印? – 2015-01-15 16:03:07

回答

4

在Python中,通常在行緩衝模式中打開終端(或更準確地說,tty)的輸出。當你使用管道時,Python將使用一個固定大小的不同緩衝區。

這意味着當您使用換行符寫文本時,緩衝區在打印到終端時會自動刷新,但對於管道,只有在緩衝區已滿或強制刷新時纔會刷新緩衝區(例如何時Python腳本退出)。

換句話說,在寫入終端時,在運行rsync命令之前,第一條打印行會刷新到終端。當重定向到管道時,文本保存在一個緩衝區中,運行rsync命令輸出(在刷新時寫入管道,至少在結束時寫入一次,但可能更頻繁),之後再向緩衝區寫入更多內容並且Python存在時該緩衝區會刷新到管道。

您可以強制手動刷新:

import sys 

# .... 
print "Hello at first" 
sys.stdout.flush() 
call(["rsync", "-aHvz", "[email protected]:/tmp/a", '.']) 
print "Hello at the end" 
sys.stdout.flush() 
+0

upvote。更正:如果引用了一個tty(對於'基於stdio'的程序(例如'python2')通用的'sys.stdout'(和子進程寫入的C stdout流)可能會被行緩衝。終端編輯模式(原始,行)在這裏是不相關的。 – jfs 2015-01-15 17:54:29

+0

@ J.F.Sebastian:合格;我習慣性地將其稱爲一個終端,但實際上已經使用了物理終端,這是不正確的。 – 2015-01-15 17:58:19

+0

沒有。我的意思是'sys.stdout' * Python對象*,C'stdout'(*'FILE *'*)(程序屬性 - 內部)不同於*終端*('stty'可能會改變它的參數)。後者在程序之前/之中/之後存在(外部)。 **過程中的緩衝區是**。 – jfs 2015-01-15 18:06:49

相關問題