Я пишу графический обработчик 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' &
I ' m, используя FIFO вместо прямого канала, чтобы позволить им работать асинхронно и разрешить уничтожение git, если окно zenity закрыто.
Проблема в том, что единственная строка, которая появляется из вывода git, является первой:
Initialized empty Git repository in /home/delan/a/.git/
Другие строки с подсчетом объектов и т. д. не отображаются или отображаются на терминале.
Текущая причина
Текущее согласие относительно того, почему это не работает, похоже, состоит в том, что cat
не является блокирует и завершает работу после первой строки, передавая только это в zenity, а не все остальное. Моя цель - принудительно заблокировать чтение и сделать так, чтобы в диалоговом окне с текстовой информацией zenity постепенно отображался весь вывод.
git
выводит сообщения о ходе выполнения (все, кроме сообщения «Инициализировано») на stderr, но в тот момент, когда я пытаюсь pipe stderr в файл или для слияния с stdout, сообщения исчезнут.
Попытка исправления 1
Я попытался написать две блокирующие версии функций cat на C, хлеб и 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'ing и проверки исходного кода git я поймите, что git выводит всю информацию о своем прогрессе (что-либо, кроме "Initialized" message) на 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 &