У меня есть команда, которая создает очень подробный вывод, порядка сотен строк в секунду. Однако команда использует \r
для перезаписи предыдущей строки вывода, подобно полосе прогресса. Иногда она записывает новую строку в терминал, что «запекает» текущую строку вывода.
При перенаправлении этого вывода в файл я получаю сотни мегабайт вывода — каждая строка записывается в файл, а не «перезаписывается» при возврате каретки.
Я понимаю, что это ожидаемое поведение, и что один из способов решения этой проблемы — сделать программу умнее и осознать, что она перенаправляется в файл, а не выводить этот интерактивный статус. Однако я не могу изменить эту программу.
Есть ли способ передать/отфильтровать этот вывод так, чтобы в конечном выходном файле оказалось то же самое, что я увидел бы, запустив его в интерактивном режиме на терминале?
Я пробовал:
spammy_cr_command | uniq
... который выводит то же самое, что и без негоuniq
а также:
spammy_cr_command | sed '/\r/d'
... который также удаляет «запеченные» строки, содержащие символ новой строки.
решение1
cmd | sed -e 's/.*\r//' > file
Это заменит весь текст в каждой строке, за которой следует возврат каретки, ничем, оставив только часть строки после последнего возврата каретки. Это необязательното же самое, что осталось бы на терминале, но в большинстве случаев это близкое к истине значение.
В частности, случай, когда строка длиннее, чем ее последующая строка, не обрабатывается. Эта программа даст неверные результаты:
printf 'abcdefg\rxyz\n'
printf '123456789\r\nxyz\n'
потому что то, что останется после себя, это будет видно
xyzdefg
123456789
xyz
но он sed
также пропустит все нестертые символы и даст
xyz
xyz
Вы можете определить, ведет ли себя ваша программа так или нет. Нередко бывает так, что индикаторы выполнения и т. п. оставляют курсор на левом краю, что может не дать желаемого результата.
решение2
Для очень примитивного вывода TTY-37 col
команда решает эту проблему без проблем, sed
упомянутых в ответе М. Гомера. (Для вывода, который не является простым выводом TTY-37 и содержит последовательности выхода терминала и управления, ни , col
ни не sed
являются инструментом для этой работы; но на Stack Exchange был вопрос и ответ начто(В течение почти восьми лет.)
%( printf 'abcdefg\rxyz\n' printf '123456789\r\nxyz\n' ) | кол -б xyzdefg 123456789 хyz %
решение3
Нечто более близкое к поведению перезаписи можно реализовать с помощью GNU awk:
BEGIN {
RS = "[\r\n]" # split records on either CR or LF
a = "" # variable to save the text for overwriting
}
{
a = $0 substr(a, 1 + length) # save current line, add trailing part of saved text
}
RT ~ /\n/ { # LF, time to print and reset
print a;
a = ""
}
Используя пример Майкла Гомера:
~ awk 'BEGIN { RS="[\r\n]" } {a = $0 substr(a, 1 + length)} RT ~ /\n/ {print a; a=""}' foo
xyzdefg
123456789
xyz
RT
Для переменной, содержащей текст разделителя записей, соответствующий RS
регулярному выражению для этой записи, необходим GNU awk .