Как выполнить grep в реальном времени для вывода, содержащего индикатор выполнения?

Как выполнить grep в реальном времени для вывода, содержащего индикатор выполнения?

Я использую инструмент ( openocd), который печатает много мусора, затем базовый индикатор выполнения, медленно печатающий простые точки, затем снова какой-то мусор.

Я хотел бы отфильтровать этот вывод так, grepчтобы отображалась только строка с индикатором выполнения, причем в режиме реального времени (т.е. каждая выведенная точка openocdнемедленно выводилась в терминале):

openocd <args> |& grep '^\.'

Проблема в том, что grepстрока буферизуется (в лучшем случае), поэтому индикатор выполнения не будет отображаться, пока она не будет завершена.

Как мне сделать с grep, или есть ли стандартная альтернатива для достижения этого? Если есть способ через openocdконфигурацию, это было бы полезно, хотя я бы предпочел более общее решение.

решение1

Это своего рода хакерский/необычный ответ, поскольку, скорее всего, это возможно не совсем чистым способом.


grepсам по себе, похоже, выводит вывод только при обнаружении символа новой строки, ваш индикатор выполнения, вероятно, не вводит символ новой строки при обновлении, отсюда и ваша проблема.

strace— это инструмент, используемый для просмотра системных вызовов, вызываемых командой. Сюда входят такие операции, как чтение и запись в память/хранилище, а также открытие/закрытие файловых дескрипторов.


С straceвы можете просмотреть, к чему обращается процесс, в случае, если ваш канал stoutпередается в grep, поэтому с straceвы можете просмотреть текст, который передается в grep. straceбудет регулярно отправляться вывод, поступающий из переданной по каналу команды, и вы можете прослушать этот вывод и отобразить его. Я тестировал с rsync --progress, который, похоже, сталкивается с похожим сценарием. Я использовал grepна , ##%потому что это то, что rsyncиспользуется для отображения прогресса.

rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%"

Если вы запустите эту команду, то обнаружите, что она straceне дает хорошего вывода, но когда я ее использовал, она straceпоймала пару reads из , rsyncкоторые grepобычно не появляются write, показывая reads для 0%, 21%, 45%, 68%, 91% и 100%, и, похоже, обновлялась примерно каждую секунду (вероятно, исходя из того, как часто rsyncобновляется прогресс).

Таким образом, с помощью этого можно получить не очень приятный grepвывод strace, вызвав то же самое grepснова.

rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%" 2>&1 > /dev/null | grep -o "[0-9]*%"

Важно 2>&1, потому что straceпечатает на stderr. > /dev/nullПеренаправляет stdoutна , /dev/nullчтобы предотвратить вывод первого, grepкоторый будет сообщен. Конечным результатом этого был следующий вывод:

0%
21%
45%
68%
91%
100%

Вам придется заменить grep, но, похоже, это сработает. Это некрасиво, но это работает и обходит ограничения grep. Кажется, что , grep -fкоторый работает как , tail -fбыл бы удобен (я знаю, grep -fчто уже используется).

Первый вариант grepв основном нужен для фильтрации текста, который straceбудет отображаться, поскольку в вызовах s readбудут перечислены только соответствующие строки , но вам также нужно что-то, через что будет проходить текст, чтобы вы могли его отслеживать.stracereadstrace

решение2

Я трачу деньги на ответ в Centimane, так как окончательный ответ довольно сложен.

Это и так было довольно халтурно... теперь это становится действительно паршиво:

make flash \
    |& strace -e trace=read grep -e "^\." -e rror \
    |& stdbuf -o0 sed -ne 's/^.*"\.".*/\./p;/rror/p' \
    | stdbuf -o0 tr -d '\n' \
    ; echo

Итак, make flashвышеизложенное — это призыв openocd;

straceиспользует описанный выше взлом Centimane;

sedзаменить read(0, ".", xxx)строки на одинарные .;

trсохраняет все .на одной строке, а окончательное эхо ставит единственный EOL.

В дополнение к этому, вызываются sedи , которые устанавливают размер буфера stdout в 0 (так как удален конец строки), а также сопоставляются для вывода некоторого мусора в случае ошибки.trstdbuf -o0grep/sed(e)rror

Я попытался свести все это раздувание к минимуму, но не смог добиться большего.

Обратите внимание, что я использую zsh/Ubuntu 14.04 и не уверен, что это будет работать на других Unix.

Связанный контент