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>).
虽然我不知道这是不是你想要的.
首先,输出重定向是从右到左解析的,所以
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可以揭示你正在开火的过程的内部运作.对于缺乏经验的命名管道,与普通管道相比,情况更糟.