代码之家  ›  专栏  ›  技术社区  ›  Delan Azabani

git stderr输出无法管道

  •  13
  • Delan Azabani  · 技术社区  · 14 年前

    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的文本信息对话框逐步显示所有输出。

    git

    修复尝试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现在什么也没有显示。

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

    修复尝试3

    在对git的源代码进行了一些跟踪和检查之后,我意识到git在stderr上输出了它的所有进度信息(任何超过“Initialized”消息的内容),这是第一行,我假设这是因为cat在EOF的早期退出,这是一个巧合/误导性的假设(git直到程序结束才停止EOF)。

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

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

    这与我所知道的关于stderr和重定向的一切相反;我甚至编写了一个在stderr和stdout上输出的小C程序来向自己证明重定向对git不起作用。

    根据Jakub Narbski的回答,以及我发给git邮件列表的邮件的回复, --progress 是我需要的选择。请注意,此选项仅在命令之后才起作用,而不是在命令之前 clone

    成功!

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

    3 回复  |  直到 14 年前
        1
  •  18
  •   Jakub Narębski adamtaub    14 年前

    我认为,当输出为 不是终点站 (tty)。我不确定这是否适用于你的案子,但试着通过 --progress “git clone”选项(即使用 git clone --progress <repository>

    但我不知道这是不是你想要的。

        2
  •  6
  •   mvds    14 年前

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

    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 可能会对你正在启动的进程的内部工作有一些启示。对于没有经验的人来说,命名管道比普通管道更糟糕。

        3
  •  1
  •   Jonathan Leffler vy32    14 年前

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

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