Я пишу графический обработчик URI для git://связей с bash и zenity, и я использую диалог zenity 'text-info' для отображения вывода clone git во время его работы, используя трубопроводы FIFO. script длиной около 90 строк, поэтому я не буду размещать его здесь, но здесь наиболее важные строки:
git clone "$1" "$target" 2>&1 | cat >> /tmp/githandler-fifo &
cat /tmp/githandler-fifo | zenity --text-info --text='Cloning git repository' &
Я использую FIFO вместо прямого канала, чтобы позволить им запускать асинхронно и разрешать убийство git, если окно zenity закрыто.
Проблема заключается в том, что первая строка, выводимая из вывода git, является первой:
Initialized empty Git repository in /home/delan/a/.git/
Другие строки с подсчетом объектов и т.д. не отображаются или отображаются на терминале.
Текущая причина
Нынешний консенсус относительно того, почему это не работает, кажется, что cat
не блокирует и завершает работу после первой строки, только передавая это на зенит, а не на остальных. Моя цель состоит в том, чтобы принудительно блокировать чтение, а диалоги с информацией о zenity-тексте показывают все выходные данные постепенно.
git
выводит сообщения о выполнении (ничего, кроме сообщения "Инициализировано" ) на stderr, но в тот момент, когда я пытаюсь передать stderr в файл или сливаться с stdout, сообщения исчезают.
Исправить попытку 1
Я попытался написать две блокирующие версии функций cat в C, 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, но пока еще не решили проблему. На данный момент, используя один, другой или оба, работает теоретически, но на практике зенит вообще ничего не показывает.
Исправить попытку 2
@mvds предположил, что использование обычного файла в комбинации с tail -f
, а не cat
может сделать это. Удивлен в таком простом решении (спасибо!) Я попробовал это, но, к сожалению, только первая строка появилась в зените и ничего больше.
Исправить попытку 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
В ответ на ответ Jakub Narębski, а также ответы на письма, отправленные в список рассылки git, --progress
- это нужная мне опция. Обратите внимание, что этот параметр работает только после команды, а не до clone
.
Успех!
Большое спасибо за вашу помощь. Это фиксированная линия:
git clone "$1" "$target" --progress > /tmp/githandler-fifo 2>&1 &