【问题标题】:git stderr output can't pipegit stderr 输出无法通过管道传输
【发布时间】:2011-05-03 01:10:04
【问题描述】:

我正在为带有 bash 和 zenity 的 git:// 链接编写图形 URI 处理程序,并且我正在使用 zenity 'text-info' 对话框来显示 git 在运行时使用 FIFO 管道的克隆输出。该脚本大约有 90 行长,所以我不会在这里发布它,但这里是最重要的几行:

git clone "$1" "$target" 2>&1 | cat >> /tmp/githandler-fifo &
cat /tmp/githandler-fifo | zenity --text-info --text='Cloning git repository' &

我使用 FIFO 而不是直接管道,以允许它们异步运行并允许在 zenity 窗口关闭时杀死 git。

问题是,从 git 的输出中出现的唯一一行是第一行:

Initialized empty Git repository in /home/delan/a/.git/

带有计数对象等的其他行不显示或显示在终端上。

当前原因

目前关于为什么这不起作用的共识似乎是cat 是非阻塞的并且在第一行之后退出,只将其传递给 zenity 而不是其余的。我的目标是强制阻止读取,并让 zenity 的文本信息对话框逐步显示所有输出。

git 在 stderr 上输出进度消息(除了“初始化”消息之外的任何内容),但是当我尝试将 stderr 传输到文件或与 stdout 合并时,消息消失了。

修复尝试 1

我尝试用 C 语言编写 cat 函数的两个阻塞版本,bread 和 bwrite,如下所示:

#include <stdio.h>
main(int argc, char **argv) {
    int c;
    for (;;) {
        freopen(argv[1], "r", stdin);
        while ((c = getchar()) != EOF)
            putchar(c);
    }
}

#include <stdio.h>
main(int argc, char **argv) {
    int c;
    for (;;) {
        freopen(argv[1], "w", stdout);
        while ((c = getchar()) != EOF)
            putchar(c), fputs("writing", stderr);
    }
}

它们工作得很好,因为它们会阻止并且不会在 EOF 上退出,但它还没有完全解决问题。目前,使用其中一个、另一个或两者在理论上可行,但在实践中,zenity 现在什么都没有显示。

修复尝试 2

@mvds 建议使用常规文件,结合tail -f 而不是cat,可以做到这一点。对如此简单的解决方案感到惊讶(谢谢!)我试过了,但不幸的是,只有第一行出现在 zenity 中,没有别的。

修复尝试 3

在做了一些 strace'ing 和检查 git 的源代码之后,我意识到 git 在 stderr 上输出其所有进度信息(任何超出“初始化”消息的内容),事实上这是第一行,我假设它是因为 cat 在 EOF 早期退出是一个巧合/错误的假设(git 在程序结束之前不会 EOF)。

情况似乎变得简单了很多,因为我不应该对原始代码进行任何更改(在问题的开头),它应该可以工作。然而,奇怪的是,stderr 输出在重定向时会“消失”——这只是 git 中发生的事情。

测试用例?试试这个,看看你是否在文件中看到任何东西(你不会):

git clone git://anongit.freedesktop.org/xorg/proto/dri2proto 2> hurr

这与我所知道的关于 stderr 和重定向的一切背道而驰;我什至写了一个小 C 程序,它在 stderr 和 stdout 上输出,以向自己证明重定向对 git 不起作用。

修复尝试 4

根据 Jakub Narębski 的回答,以及对我发送到 git 邮件列表的电子邮件的回复,--progress 是我需要的选项。请注意,此选项仅在命令之后有效,而在 clone 之前无效。

成功了!

非常感谢您的所有帮助。这是固定线路:

git clone "$1" "$target" --progress > /tmp/githandler-fifo 2>&1 &

【问题讨论】:

  • 天哪……你救了我的命……碰巧遇到了同样的问题
  • 成功!感谢那。 --progress 对我来说是拼图中缺失的部分。

标签: git bash pipe named-pipes zenity


【解决方案1】:

我认为当输出不是终端 (tty) 时,至少有一些进度报告会被静音。我不确定它是否适用于您的情况,但请尝试将 --progress 选项传递给“git clone”(即使用git clone --progress &lt;repository&gt;)。

虽然我不知道是不是你想要的。

【讨论】:

  • 我怀疑这可能是它。它也很容易测试 - 只需重定向到普通文件而不是 FIFO 和小提琴,直到你知道你有你想要的输出。
  • 不幸的是,git 输出“未知选项:--progress”,然后是换行符,然后是语法/用法摘要。有趣的是,这一次,都是 zenity 上的输出,并且 FIFO 有效。此外,git 完全输出到文件中;罪魁祸首可能是 zenity 的非阻塞读取。
  • @Delan:啊,所以不是这个。 (至于--progress 选项,大概这意味着您使用的 git 版本太旧 - 该功能是在 v1.7.1 中添加的。)
  • @Delan:实际上,我有点困惑,看着你所有的 cmets。您在这里说它可以很好地转到文件,但在其他地方您说如果您尝试重定向 stderr 它就会消失。是哪个?
  • 奇怪的是,我使用的是 1:1.7.1-1.1(应该不会太旧)但它仍然不会占用--progress
【解决方案2】:

一方面,输出重定向是从右到左解析的,所以

git clone "$1" "$target" 2>&1 > /tmp/githandler-fifo &

不等于

git clone "$1" "$target" > /tmp/githandler-fifo 2>&1 &

后者会将stderr重定向到stdout,然后将stdout(包括stderr)重定向到文件。前者会将stdout重定向到文件,然后在stdout上显示stderr。

至于到zenity 的管道(我不知道),我认为您可能使用命名管道使事情变得过于复杂。使用strace 可能会对您正在启动的进程的内部工作原理有所了解。对于没有经验的人来说,命名管道比普通管道更糟糕。

【讨论】:

  • 我使用命名管道的目的仅仅是为了能够同时为 git 和 zenity 提供背景,这样我就可以检查 zenity 是否在 git 之前退出,如果发生这种情况则终止 git。感谢您让我知道从右到左的重定向解析。我已经尝试过了,但它并不能完全解决这里的问题。现在,第一行出现在 zenity 中,其余的都不显示在任何地方(甚至在终端中也不显示)。
  • 作为一种不太复杂的替代方法,您可能希望重定向到一个文件,然后通过管道传输tail -f。这避免了典型的命名管道问题。
  • 关于从右到左的重定向执行——这只是错误。重定向按自然顺序执行。重定向2&gt;&amp;1 &gt;file 处理如下:在第一次重定向之后,fd 2 指向与 fd 1 相同的文件(即,什么是标准输出,例如终端)。在第二次重定向之后,fd 1 指向file,fd 2 仍然指向终端,因为重定向是在 before fd 1 更改之前进行的。
  • @mvds,我已经尝试过了(将 git 重定向到常规文件并将 tail -f 管道传输到 zenity),它适用于第一行,但进一步的输出显示在终端上。也许 git 正在做一些奇怪的终端魔术?
  • @Delan,如果正确的顺序是这种情况(感谢@Roman 的澄清),您应该strace git 找出发生了什么。
【解决方案3】:

鉴于使用名为“a”的 FIFO 进行的实验,我认为问题在于 zenity 处理其输入的方式。如果您从键盘输入 zenity 会发生什么? (怀疑:它的行为如您所愿,读取 EOF。)但是,zenity 可能使用常规阻塞 I/O 处理终端输入(tty 输入),但对所有其他设备类型使用非阻塞 I/O。非阻塞 I/O 适用于来自文件的输入;对于来自管道或 FIFO 等的输入不太理想。如果它确实使用非阻塞 I/O,zenity 将获得第一行输出,然后退出循环,认为它已完成,因为它的第二次读取尝试表明没有其他东西可以立即使用。

证明这是正在发生(或未发生)的事情将是棘手的。我会寻找 'truss' 或 'strace' 或其他系统调用监视器来跟踪 zenity 正在做什么。

至于解决方法...如果假设是正确的,那么您需要说服 zenity 它是从终端而不是 FIFO 读取的,因此您可能需要安装一个伪 tty(或pty);第一个进程将写入 pty 的主端,您将安排 zenity 从 pty 的从端读取。您也可能仍然使用 FIFO - 尽管它会产生很长的命令链。

【讨论】:

    猜你喜欢
    • 2015-03-30
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多