Я пишу графический обработчик URI для ссылок git: // с bash и zenity, и я использую диалоговое окно 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 вместо прямого канала, чтобы позволить им работать асинхронно и убивать git, если окно zenity закрыто.
Проблема в том, что единственная строка, которая появляется из вывода git, является первой:
Initialized empty Git repository in /home/delan/a/.git/
Другие строки с подсчетом объектов и т. Д. Не отображаются или отображаются на терминале.
Текущая причина
Текущий консенсус относительно того, почему это не работает, похоже, что cat
неблокирует и выходит после первой строки, передавая его только zenity, а не остальным. Моя цель состоит в том, чтобы принудительно заблокировать чтение, и чтобы диалоговое окно с текстовой информацией zenity показывало все результаты постепенно.
git
выводит сообщения о ходе выполнения (все, кроме сообщения «Initialized») на 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, но это еще не решило проблему. В настоящее время использование одного, другого или обоих работает в теории, но на практике zenity сейчас вообще ничего не показывает.
Попытка исправить 2
@ mvds предположил, что использование обычного файла в сочетании с tail -f
вместо cat
может сделать это. Удивленный таким простым решением (спасибо!), Я попробовал его, но, к сожалению, только первая строка показалась в зените и больше ничего.
Попытка исправить 3
После некоторого изучения и проверки исходного кода git я понимаю, что git выводит всю свою информацию о прогрессе (что угодно, кроме сообщения «Initialized») на stderr, и тот факт, что это первая строка, и я предполагаю, что это из-за того, что cat рано выходил из EOF, это было совпадение / ошибочное предположение (git не EOF, пока программа не завершится).
Ситуация, казалось, стала намного проще, поскольку мне не нужно было ничего менять по сравнению с исходным кодом (в начале вопроса), и это должно сработать. Однако при загадочных обстоятельствах вывод stderr «исчезает» при перенаправлении - и это только то, что происходит в git.
контрольный пример? Попробуйте это, и посмотрите, видите ли вы что-нибудь в файле (вы не увидите):
git clone git://anongit.freedesktop.org/xorg/proto/dri2proto 2> hurr
Это идет вразрез со всем, что я знаю о stderr и перенаправлении; Я даже написал небольшую C-программу, которая выводит на stderr и stdout, чтобы доказать себе, что перенаправление просто не работает для git.
Попытка исправить 4
В соответствии с ответом Якуба Наребски, а также ответами на электронные письма, которые я отправил в список рассылки git, --progress
- это вариант, который мне нужен. Обратите внимание, что этот параметр работает только после команды, а не до clone
.
Успех!
Большое спасибо за вашу помощь. Это фиксированная линия:
git clone "$1" "$target" --progress > /tmp/githandler-fifo 2>&1 &