如何使用fork()exec()捕获git clone输出

时间:2016-02-29 13:37:16

标签: c git

这是我的full code,我使用:

    char *args[] = {"git", "clone", "https://github.com/thinker3/youdao.git", "/tmp/youdao", NULL};

    if (execv("/usr/bin/git", args) < 0) {
        perror("error on exec");
        exit(0);
    }

在child中运行cmd,并使用:

捕获输出
    char buffer[1024];
    close(pipefd[1]);  // close the write end of the pipe in the parent
    while (read(pipefd[0], buffer, sizeof(buffer)) != 0) {
        std::cout << buffer << std::endl;
    }

在超级过程中,我得到了

Cloning into '/tmp/youdao'...

但我希望得到像终端一样的输出,怎么做?

roroco@roroco-Zhaoyang-K49 /tmp $ git clone https://github.com/thinker3/youdao.git
Cloning into 'youdao'...
remote: Counting objects: 434, done.
remote: Total 434 (delta 0), reused 0 (delta 0), pack-reused 434
Receiving objects: 100% (434/434), 221.51 KiB | 140.00 KiB/s, done.
Resolving deltas: 100% (275/275), done.
Checking connectivity... done.

更新

当然,我可以用libgit2来做,但这只是一个问题:为什么我不能得到git clone完整的标准输出

1 个答案:

答案 0 :(得分:3)

显然,根据git版本存在细微差别,因此我将描述我测试过的两个版本的行为。在这两个版本之间的某个时间,行为从第一个变为第二个。

git版本1.8.3

git写入stdout的输出中唯一的部分是:

Cloning into 'youdao'...

其余部分,实际的克隆进度,只有在stderr附加到终端时才会写入stderr。要使其始终将进度发送到stderr,即使它未附加到终端(例如您的情况),也必须使用--progress进行调用。见man git-clone

  

- 进度

     

默认情况下,标准错误流在连接到终端时会报告进度状态,除非指定了-q。即使标准错误流未定向到终端,此标志也会强制进度状态。

添加此参数后,您还必须:

  • 修复从管道读取的代码(read()返回读取的字节数,并且不终止缓冲区);
  • 解析您将在stderr上获得的进度,因为它不会像您在终端中看到的那样格式化。

稍后编辑

从评论来看,这似乎不够明确,所以让我试着说得更清楚。

如果在终端中输入如下命令:

$ git clone "https://github.com/thinker3/youdao.git"

您将在终端获得此输出:

Cloning into 'youdao'...
Receiving objects: 100%
... (rest of progress info)

如果您输入这样的命令:

$ git clone "https://github.com/thinker3/youdao.git" 1>output.log

你会在output.log中得到这个:

Cloning into 'youdao'...

在终端上:

Receiving objects: 100%
... (rest of progress info)

这意味着gitCloning into...写入标准输出流(您已在文件中重定向)以及标准错误流上的进度信息,这些信息已保留在终端上。< / p>

如果您在终端上输入如下命令:

$ git clone "https://github.com/thinker3/youdao.git" 2>output.log

你会在终端上得到这个:

Cloning into 'youdao'...

因为我们已经确定这将是stdout,你在终端上留下了stdout。

该文件将为空!该帖子为空的原因由帖子开头的粗体文字描述。具体来说,git仅在stderr转到终端时才会将进度信息打印到stderr 。在这种情况下,stderr不会转到终端,因为您已将其重定向到某个文件,因此git根本不会打印进度信息。

如果你想迫使git将这个进度信息打印到stderr,即使stderr没有附加到终端,你必须明确地告诉它,如原始答案中所述,指定 - -progress git clone,如下所示:

$ git clone --progress "https://github.com/thinker3/youdao.git" 2>output.log

现在,使用额外参数并将stderr重定向到文件,您将在文件中找到进度信息。然而,它不会像你在终端上看到的那样格式化。这就是为什么我在原始答案中提到你必须解析并理解你从那个管道上读到的东西。

git version 2.5.0

与上述描述的不同之处在于,现在输出的第一行Cloning into 'youdao'...也转到stderr,并且此行(与进度信息文本的其余部分相对)无论是否写入stderr stderr是否连接到终端。只有当错误流进入终端时,其余的进度信息文本才会像以前一样发送到stderr。

所以现在你没有我上面几次提到的额外参数:

$ git clone "https://github.com/thinker3/youdao.git" 2>output.log
$ cat output1.log 
Cloning into 'youdao'...

并使用额外的参数:

$ git clone --progress "https://github.com/thinker3/youdao.git" 2>output.log
$ cat output.log 
Cloning into 'youdao'...
remote: Counting objects: 434, done.        
remote: Total 434 (delta 0), reused 0 (delta 0), pack-reused 434        
Receiving objects: 100% (434/434), 221.51 KiB | 135.00 KiB/s, done.
Resolving deltas: 100% (275/275), done.
Checking connectivity... done.

结论

如果您希望能够通过该管道获取完整的进度信息文本,则必须使用 - 进度致电git clone

原始答案的其余部分保持不变:

  • 您必须修复管道读取代码
  • 您必须解析通过管道输出的输出,因为它与您在终端或文件中看到的输出不同。