Joh*_*n A 74 python subprocess stdout
我想subprocess.Popen()
在Windows中使用rsync.exe,并在Python中打印stdout.
我的代码有效,但在文件传输完成之前它没有抓住进度!我想实时打印每个文件的进度.
现在使用Python 3.1,因为我听说它应该更好地处理IO.
import subprocess, time, os, sys
cmd = "rsync.exe -vaz -P source/ dest/"
p, line = True, 'start'
p = subprocess.Popen(cmd,
shell=True,
bufsize=64,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
for line in p.stdout:
print(">>> " + str(line.rstrip()))
p.stdout.flush()
Run Code Online (Sandbox Code Playgroud)
nos*_*klo 92
一些经验法则subprocess
.
shell=True
.它不必要地调用一个额外的shell进程来调用你的程序.sys.argv
在蟒蛇是一个列表,所以是argv
在C.所以你传递一个列表来Popen
调用子进程,而不是一个字符串.stderr
到a PIPE
.stdin
当你不写信时,不要重定向.例:
import subprocess, time, os, sys
cmd = ["rsync.exe", "-vaz", "-P", "source/" ,"dest/"]
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''):
print(">>> " + line.rstrip())
Run Code Online (Sandbox Code Playgroud)
也就是说,rsync很可能在检测到它连接到管道而不是终端时缓冲其输出.这是默认行为 - 当连接到管道时,程序必须显式刷新stdout以获得实时结果,否则标准C库将缓冲.
要测试它,请尝试运行此代码:
cmd = [sys.executable, 'test_out.py']
Run Code Online (Sandbox Code Playgroud)
并创建一个test_out.py
包含以下内容的文件:
import sys
import time
print ("Hello")
sys.stdout.flush()
time.sleep(10)
print ("World")
Run Code Online (Sandbox Code Playgroud)
执行该子进程应该给你"Hello"并在给出"World"之前等待10秒.如果上面的python代码发生了这种情况而不是rsync
,那就意味着rsync
它本身就是缓冲输出,所以你运气不好.
解决方案是pty
使用类似的东西直接连接到a pexpect
.
Elv*_*vin 37
我知道这是一个古老的话题,但现在有一个解决方案.使用选项--outbuf = L调用rsync.例:
cmd=['rsync', '-arzv','--backup','--outbuf=L','source/','dest']
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, b''):
print '>>> {}'.format(line.rstrip())
Run Code Online (Sandbox Code Playgroud)
Lin*_*ing 13
在Linux上,我遇到了摆脱缓冲的同样问题.我终于使用了"stdbuf -o0"(或者来自期望的unbuffer)来摆脱PIPE缓冲.
proc = Popen(['stdbuf', '-o0'] + cmd, stdout=PIPE, stderr=PIPE)
stdout = proc.stdout
Run Code Online (Sandbox Code Playgroud)
然后我可以在stdout上使用select.select.
另见https://unix.stackexchange.com/questions/25372/
for line in p.stdout:
...
Run Code Online (Sandbox Code Playgroud)
总是阻塞,直到下一个换行.
对于"实时"行为,您必须执行以下操作:
while True:
inchar = p.stdout.read(1)
if inchar: #neither empty string nor None
print(str(inchar), end='') #or end=None to flush immediately
else:
print('') #flush for implicit line-buffering
break
Run Code Online (Sandbox Code Playgroud)
当子进程关闭其stdout或退出时,将保留while循环.
read()/read(-1)
将阻止,直到子进程关闭其stdout或退出.
你的问题是:
for line in p.stdout:
print(">>> " + str(line.rstrip()))
p.stdout.flush()
Run Code Online (Sandbox Code Playgroud)
迭代器本身有额外的缓冲.
尝试这样做:
while True:
line = p.stdout.readline()
if not line:
break
print line
Run Code Online (Sandbox Code Playgroud)
小智 6
你不能让stdout打印无缓冲到管道(除非你可以重写打印到stdout的程序),所以这是我的解决方案:
将stdout重定向到没有缓冲的sterr. '<cmd> 1>&2'
应该这样做.按如下方式打开进程:myproc = subprocess.Popen('<cmd> 1>&2', stderr=subprocess.PIPE)
您无法区分stdout或stderr,但会立即获得所有输出.
希望这有助于任何人解决这个问题.
小智 5
p = subprocess.Popen(command,
bufsize=0,
universal_newlines=True)
Run Code Online (Sandbox Code Playgroud)
我正在用 python 编写 rsync 的 GUI,并且有相同的问题。这个问题困扰了我好几天,直到我在 pyDoc 中找到了这个问题。
如果 universal_newlines 为 True,则文件对象 stdout 和 stderr 将在通用换行模式下作为文本文件打开。行可以由 '\n'(Unix 行尾约定)、'\r'(旧的 Macintosh 约定)或 '\r\n'(Windows 约定)中的任何一个终止。所有这些外部表示形式都被 Python 程序视为“\n”。
似乎 rsync 在翻译时会输出 '\r' 。
根据使用情况,您可能还希望禁用子流程本身中的缓冲。
如果子进程将是Python进程,则可以在调用之前执行此操作:
os.environ["PYTHONUNBUFFERED"] = "1"
Run Code Online (Sandbox Code Playgroud)
或者将其作为env
参数传递给Popen
。
否则,如果您使用的是Linux / Unix,则可以使用该stdbuf
工具。例如:
cmd = ["stdbuf", "-oL"] + cmd
Run Code Online (Sandbox Code Playgroud)
另请参见这里约stdbuf
或其他选项。
将 rsync 进程的标准输出更改为无缓冲。
p = subprocess.Popen(cmd,
shell=True,
bufsize=0, # 0=unbuffered, 1=line-buffered, else buffer-size
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
99893 次 |
最近记录: |