我正在使用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上输出进度信息(除了“Initialized”消息之外的任何内容),但是当我尝试将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`和检查`git`源代码,我意识到`git`将所有的进度信息(在“Initialized”消息之后的任何内容)输出到标准错误`stderr`上,并且这是第一行以及我认为是因为`cat`在EOF时早早退出所以导致这种情况的假设是巧合/误导的假设(`git`直到程序结束才会EOF)。
情况似乎变得简单多了,因为我不需要从原始代码(在问题开头)更改任何东西,它应该可以正常工作。然而,奇怪的是,当重定向时,标准错误输出会“消失”,这只发生在`git`中。
测试用例?尝试这个,看看文件中是否有任何内容(你不会看到任何东西):
git clone git://anongit.freedesktop.org/xorg/proto/dri2proto 2> hurr
这与我所知道的关于stderr和重定向的一切都不符;我甚至编写了一个小的C程序,以证明重定向对于git来说根本行不通。
尝试修复4
根据Jakub Narębski的回答以及我发送到git邮件列表的回复,--progress
是我需要的选项。请注意,此选项仅在命令之后生效,而不是在clone
之前。
成功!
非常感谢您的所有帮助。这是修复后的命令:
git clone "$1" "$target" --progress > /tmp/githandler-fifo 2>&1 &