git stderr输出无法管道

Del*_*ani 13 git bash pipe named-pipes zenity

我正在使用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' &
Run Code Online (Sandbox Code Playgroud)

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

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

Initialized empty Git repository in /home/delan/a/.git/
Run Code Online (Sandbox Code Playgroud)

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

目前的原因

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

git 在stderr上输出进度消息(除了"Initialized"消息之外的任何内容),但是当我尝试将stderr管道传输到文件或与stdout合并时,消息就会消失.

修复尝试1

我试图在C,面包和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);
    }
}
Run Code Online (Sandbox Code Playgroud)

它们很好地工作,因为它们阻止并且不会退出EOF,但它还没有完全解决问题.目前,使用一个,另一个或两者,在理论上起作用,但在实践中,zenity现在根本没有显示任何东西.

修复尝试2

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

修复尝试3

在做了一些strace'ing并检查git的源代码之后,我意识到git在stderr上输出了它的所有进度信息(任何超过"Initialized"消息的信息),以及这是第一行和我的假设,因为它是因为cat在EOF早期退出是一个巧合/错误的假设(git在程序结束之前不会EOF).

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

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

git clone git://anongit.freedesktop.org/xorg/proto/dri2proto 2> hurr
Run Code Online (Sandbox Code Playgroud)

这违背了我对stderr和重定向的所有了解; 我甚至编写了一个在stderr和stdout上输出的小程序来向自己证明重定向对git不起作用.

修复尝试4

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

成功!

非常感谢您的帮助.这是固定的:

git clone "$1" "$target" --progress > /tmp/githandler-fifo 2>&1 &
Run Code Online (Sandbox Code Playgroud)

Jak*_*ski 18

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

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


mvd*_*vds 6

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

git clone "$1" "$target" 2>&1 > /tmp/githandler-fifo &
Run Code Online (Sandbox Code Playgroud)

不等于

git clone "$1" "$target" > /tmp/githandler-fifo 2>&1 &
Run Code Online (Sandbox Code Playgroud)

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

至于管道zenity(我不知道),我认为你可能会使命名管道过于复杂.使用strace可以揭示你正在开火的过程的内部运作.对于缺乏经验的命名管道,与普通管道相比,情况更糟.

  • 关于从右到左的重定向执行 - 这只是**错误**.重定向按自然顺序执行.重定向"2>&1>文件"按如下方式处理:在第一次重定向之后,fd 2指向与fd 1相同的文件(即什么是标准输出,例如终端).在第二次重定向之后,fd 1指向`file`,并且fd 2仍然指向终端,因为在*fd 1改变之前进行了重定向. (2认同)