如何在运行git命令时获取子进程stdout? [英] How to get subprocess stdout while running git command?

查看:57
本文介绍了如何在运行git命令时获取子进程stdout?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用python编写的程序,并在其中使用了git命令.由于某些原因,我不想使用git-python或其他代替子进程.但是我目前仍然无法获得 git clone 的输出.

I have a program written in python and used git command in it.. For some reason I don't want to use git-python or others instead of subprocess. But I'm currently stuck in getting git clone output.

我尝试了一些代码段.有些命令可以与 ping 8.8.8.8 之类的命令配合使用,但不能与 git clone 一样.

I've tried some code snippet. Some works fine with commands like ping 8.8.8.8, but not the git clone.

例如

使用线程

def log_worker(stdout):
    while True:
        last = non_block_read(stdout).strip() 
        if last != "":
            print(last)


def non_block_read(output):
    fd = output.fileno()
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    try:
        return output.read()
    except:
        return ''

def test():
    mysql_process = subprocess.Popen(
        "ping google.com",
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)

    thread = Thread(target=log_worker, args=[mysql_process.stdout])
    thread.daemon = True
    thread.start()

    mysql_process.wait()
    thread.join(timeout=1)

test()

newlines = ['\n', '\r\n', '\r']
def unbuffered(proc, stream='stdout'):
    stream = getattr(proc, stream)
    with contextlib.closing(stream):
        while True:
            print('tt')
            out = []
            last = stream.read(1)
            # Don't loop forever
            if last == '' and proc.poll() is not None:
                break
            print('last', last)
            while last not in newlines:
                print("loop")
                # Don't loop forever
                if last == '' and proc.poll() is not None:
                    break
                out.append(last)
                last = stream.read(1)
            out = ''.join(out)
            yield out

def example():
    cmd = ['ls', '-l', '/']
    proc = subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        # Make all end-of-lines '\n'
        universal_newlines=True,
        shell = True
    )
    for line in unbuffered(proc):
        print('new line')
        print line

example()

最常见的一个

for line in iter(proc.stdout.readline, ''):
    sys.stdout.write('{:.2f}  {}\n'.format(
        time.time() - start,
        line.rstrip()
    ))
    sys.stdout.flush()

所有这些都可以与 ping google.com 一起正常使用,但不能与 git clone 一起使用.有什么办法可以解决这个问题?预先感谢!

all of them works fine with ping google.com, but not git clone. Is there any way to solve this? Thanks in advance!

UPDATE1:面对现实,我只想获取 git clone 的最终百分比.日志或不需要任何日志文件.

UPDATE1: In face, I'm just want to get the finished percent of git clone. Log or any log files are not needed.

推荐答案

不写入终端时, git clone 没有任何输出到stdout或stderr,除非有错误.

When not writing to a terminal, git clone doesn't have any output to either stdout or stderr, except on error.

在写入终端时,当然会有很多输出,但是该输出是进度条,它们会不断被覆盖.通常,您不希望那样—它将导致大量的控制字符和重复的行.

When writing to a terminal, of course, it has lots of output—but that output is progress bars that are continually overwritten. Usually, you don't want that—it's going to be a big mess of control characters and repeated lines.

但是,如果您想要想要它,则有两种选择.

But if you do want it, there are two options.

首先,您可以使用PTY(Pseudo-TTY).您可以使用 os.openpty ,然后将PTY明确交给子进程.或者,您可以使用 os.forkpty ,它处理派生并自动挂接PTY,因此您所要做的就是调用 os.exec 函数.或者,您可以使用 pty 模块.(尚不清楚哪种方法更可移植; openpty forkpty 声称 pty 更易于移植,并且从概念上讲,它是按照这种方式设计的……但是也只在Linux上进行过真正的测试.)

First, you can use a PTY (Pseudo-TTY). You can create a PTY with os.openpty, then hand the PTY off explicitly to the child process. Or you can use os.forkpty, which handles forking and automatically hooking up the PTY so all you have to do is call one of the os.exec functions. Or you can use the pty module. (It's not entirely clear which is more portable; openpty and forkpty claim that pty is more portable, and conceptually it's designed that way… but it's also only really tested on Linux.)

请注意, git 希望PTY作为其stderr,而不是其stdout.

Note that git wants the PTY as its stderr, not its stdout.

或者,大多数 git 命令都有一个-progress 标志,即使它们不是终端,也可以使它们将进度写入stderr.至少从此处记录的版本开始,其中包括 clone ,但是您当然应该在 man 中检查您的本地版本.因此,可能就是您所需要的.(另请参见-verbose 标志.)

Alternatively, most git commands have a --progress flag that causes them to write progress to stderr even if it's not a terminal. At least as of the version documented here, this includes clone, but of course you should check the man for your local version. So, that may be all you need. (Also see the --verbose flag.)

但是,这可能不太好.对我来说,当我提供一个没有附加的Termcaps的PTY时,我得到的是每行后跟一个 \ r ,而没有 \ n 来覆盖它;当我使用-progress 选项时, git 会检测我的脚本运行的任何终端的termcaps,这意味着我最终会获得ANSI颜色代码以及 \ r s.

However, this may not be as nice. For me, when I provide a PTY with no attached termcaps, I get each line followed by a \r without \n to overwrite it; when I use the --progress option, git detects the termcaps of whatever terminal my script happens to be running it, which means I end up getting ANSI color codes as well as \rs.

当然,无论哪种方式,我都会得到数百条我不感兴趣的无用行,但是我认为那是您想要的?(或者也许您想使用 universal_newlines ='\ r''\ r'转换为'\ n'?,因为这是自覆盖的Unix终端输出,而您却装作它是经典Mac输出...但是可以用.)

Of course either way I'm getting hundreds of useless lines that I have no interest in, but I assume that's what you wanted? (Or maybe you want to use universal_newlines='\r' to translate the '\r' to '\n'? That's slightly cheating, because this is self-overwriting Unix terminal output, and you're pretending it's classic-Mac output… but it works.)

这篇关于如何在运行git命令时获取子进程stdout?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆