git stderr输出不能管道

我正在为bash和zenity编写git://链接的图形URI处理程序,并且我正在使用zenity'text-info'对话框来使用FIFO管道在运行时显示git的克隆输出。 剧本大概有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,bread和bwrite编写两个cat函数的阻塞版本,如下所示:

#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,但它还没有完全解决了这个问题。 目前,使用其中之一,或者两者兼而有之,理论上是行得通的,但在实践中,现在完全没有任何显示。

修复尝试2

@mvds建议使用常规文件,结合tail -f而不是cat ,可以做到这一点。 惊讶于这样一个简单的解决方案(谢谢!)我尝试了它,但不幸的是,只有第一行显示在zenity中,没有别的。

修复尝试3

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

情况似乎变得更简单了,因为我不应该从原始代码(在问题开始时)改变任何东西,它应该工作。 然而,神秘的是,stderr输出在重定向时'消失' - 而这只是在git中发生的事情。

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

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

这违背了我对stderr和重定向的一切了解; 我甚至写了一个C程序输出stderr和stdout来证明自己重定向对git不起作用。

修复尝试4

根据JakubNarębski的回答,以及对我发送给git邮件列表的电子邮件的回复,-- --progress是我需要的选项。 请注意,此选项仅适用于该命令,并且不适用于clone之前。

成功!

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

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


我认为,当输出不是终端(tty)时,至少有一些进度报告会变得沉默。 我不确定它是否适用于您的情况,但尝试将--progress选项传递给'git clone'(即使用git clone --progress <repository> )。

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


首先,输出重定向是从右向左解析的,所以

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可能会对您正在启动的进程的内部工作原理有所了解。 对于缺乏经验的命名管道,与普通管道相比,情况更糟糕。


考虑到FIFO的实验称为'a',我认为问题在于zenity处理其输入的方式。 如果你从键盘输入zenity会发生什么? (怀疑:它的行为就像你想要的那样,读取到EOF。)然而,它可能是zenity使用常规阻塞I / O处理终端输入(tty输入),但对所有其他设备类型使用非阻塞I / O。 非阻塞I / O适用于从文件输入; 如果它使用了非阻塞I / O,zenity会得到输出的第一行,然后退出循环,认为它已经完成,因为它的第二次读取尝试会指示没有其他东西立即可用。

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

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

链接地址: http://www.djcxy.com/p/42695.html

上一篇: git stderr output can't pipe

下一篇: How do I write stderr to a file while using "tee" with a pipe?