实时读取 git clone 的输出
我需要读取git克隆过程中的状态(正在接收对象 XXX%),但是不知道怎么做。
我在使用subprocess.Popen,但不知道怎么抓取我需要的那一行:
proc = subprocess.Popen([GIT, "-C",IDIR+"/"+REPO,"clone",URL],shell=False,bufsize=0,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
这是典型的输出:
Cloning into 'xxx'...
remote: Reusing existing pack: 5250, done.
remote: Counting objects: 1652, done.
remote: Compressing objects: 100% (1428/1428), done.
remote: Total 6902 (delta 389), reused 0 (delta 0)
Receiving objects: XXX% (6902/6902), 27.66 MiB | 1.51 MiB/s, done.
Resolving deltas: 100% (2010/2010), done.
Checking connectivity... done.
Checking out files: 100% (3266/3266), done.
编辑
我尝试了这个讨论串和另一个被建议为重复的讨论串中的所有建议,但都没有效果。
这个建议的结果是“正在克隆到'test'... 完成”,但没有其他输出:
popen = subprocess.Popen(["git", "clone", "https://github.com/xxx/test.git"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT,shell=False )
for line in popen.stdout:
print "out newline:"
print line
print "done"
这是没有包含任何状态信息的输出:
out newline:
Cloning into 'test'...
done
5 个回答
在这里,我想补充一下其他回答中提到的 stderr
和 --progress
,给大家提供一个简单的完整示例,这个示例会实时打印出 git clone 命令的执行过程:
import os
import re
import subprocess
def test():
url = 'http://github.com/octocat/Hello-World/'
output = subprocess.Popen(['git', 'clone', '--progress', url], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
fd = output.stderr.fileno()
while True:
lines = os.read(fd,1000).decode('utf-8')
lines = re.split('\n|\r', lines)
for l in lines:
if l != '':
print(l)
if len(lines) == 1:
break
print('Press enter to continue.')
首先,我建议把标准输出和错误输出合在一起,这样所有信息都能集中在一个地方。也就是说,调用Popen的时候加上stderr=subprocess.STDOUT
。
其次,你需要在执行git的时候加上--progress
这个选项,因为git-clone的手册上说:
--progress
Progress status is reported on the standard error stream by default when it is attached to a terminal, unless -q is specified. This flag forces progress status even if the standard error stream is not directed to a terminal.
而且你的git没有连接到终端。
所以代码应该像这样:
popen = subprocess.Popen(["git", "clone", "--progress", url],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
for line in popen.stdout:
print "out newline:"
print line
print "done"
我建议你去看看关于“使用subprocess获取实时输出”这个问题的回答,这样可以让你的程序更好。
我觉得用 subprocess.communicate()
就可以解决这个问题。
我一般是这样做的:
process=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutput,stderror=process.communicate()
for line in stdoutput:
if line.startswith('Receiving objects'):
print line
我猜你是想在实时通信中显示一些进度信息,而这个过程还在进行中。
问题是,普通的标准输出流是有缓冲的,也就是说它会先把信息存起来,等到一定条件满足后再一起输出。你需要的是没有缓冲的输出流。你可以通过使用os模块来实现这一点,比如:
fd = proc.stdout.fileno()
while proc.returncode is None:
l = os.read(fd, 1000) # Read a bit of data
print l
[根据评论进行了编辑]
使用 git clone
命令时加上 --progress
这个选项,可以正常显示输出。
这个方法对我有效。
import subprocess
popen = subprocess.Popen(["git", "clone", "--progress", "git@bitbucket.org:xxx/yyy.git"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in popen.stdout:
print line,
print "done"
输出结果是
$ python test.py
Cloning into 'yyy'...
remote: Counting objects: 1076, done.
remote: Compressing objects: 100% (761/761), done.
remote: Total 1076 (delta 488), reused 576 (delta 227)
Receiving objects: 100% (1076/1076), 6.24 MiB | 260.00 KiB/s, done.
Resolving deltas: 100% (488/488), done.
Checking connectivity... done.
done
[编辑]
正如 Cristian Ciupitu 指出的那样,其实你不需要使用 iter()
,直接用 for line in popen.stdout:
也能正常工作(或者根据版本不同,效果可能会有所不同)。