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

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

问题描述

我有一个用 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 = ['
', '
', '
']
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 '
'
        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}  {}
'.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!

更新1:面对现实,我只想获得 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(伪 TTY).您可以使用 os.openpty,然后将 PTY 显式交给子进程.或者你可以使用 os.forkpty,它处理分叉和自动连接 PTY,所以你所要做的就是调用 os.exec 函数.或者您可以使用 pty模块.(不完全清楚哪个更便携;openptyforkpty 声称 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 作为它的标准错误,而不是它的标准输出.

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

另外,大多数 git 命令都有一个 --progress 标志,即使它不是终端,也会导致它们将进度写入 stderr.至少从 here 中记录的版本开始,这包括 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 时,我会在每一行后面跟着一个 而没有 来覆盖它;当我使用 --progress 选项时,git 会检测到我的脚本碰巧正在运行它的任何终端的 termcaps,这意味着我最终会获得 ANSI 颜色代码以及 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 without 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 s.

当然,无论哪种方式,我都会收到数百条我不感兴趣的无用行,但我认为这就是您想要的?(或者也许您想使用 universal_newlines=' '' ' 转换为 ' '?这有点作弊,因为这是自覆盖的 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=' ' to translate the ' ' to ' '? 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 命令时如何获取子进程标准输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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