Пусть тройник лучше обрабатывает возврат каретки

658
sjngm

Я написал приложение для Java-консоли, которое неоднократно выводит свой статус на консоль, используя возврат каретки (\ r) в конце, а не перевод строки (\ n), чтобы сохранить вывод на одном экране. Я также хочу передать этот вывод в файл, как

java -jar my-jar.jar | tee /tmp/my-jar.log 

Однако не имеет смысла записывать все в этот файл, только то, что видно в конце приложения. Другими словами, мне не нужны все «строки», заканчивающиеся на \ r.

Пример: я кодирую

System.out.print("hello\r") Thread.sleep(2000); System.out.println("world") 

На экране появляется «привет», а через две секунды его заменяет «мир». Поэтому после завершения программы пользователь видит только «мир» на экране. Хорошо, это правильно.

Однако, если я передаю это в файл, он содержит «hello \ rworld \ n», но я хочу, чтобы он содержал только «world \ n».

Как мне сделать это в командной строке, а не кодировать это на Java (вот почему вопрос здесь, а не на SO)?

2

2 ответа на вопрос

2
John1024

Используя sed

По умолчанию sedчитается разделенный строкой ввод. Эта команда удалит все до последнего \rв строке:

sed 's/.*\r//' 

Например:

$ echo $'line1\n\hi\rhello\rworld' | sed 's/.*\r//' line1 world 

Чтобы использовать это с tee, мы можем использовать процесс подстановки :

echo $'line1\n\hi\rhello\rworld' | tee >(sed 's/.*\r//' >Outfile) 

В bash эта конструкция >(...)называется процессом замещения . Он запускает команды в скобках и помещает их в подобный файлу объект. teeзапись в файл-подобный объект, и команды обрабатывают ввод.

Использование awk

Точно так же это удаляет все перед последним \rв новой строке:

awk -F'\r' '' 

Опция -F'\r'устанавливает для разделителя полей возврат каретки. Следовательно, мы хотим печатать только последнее поле $NFв каждой строке, разделенной новой строкой. Таким образом, print $NF.

Например:

$ echo $'line1\n\hi\rhello\rworld' | awk -F'\r' '' line1 world 

Чтобы использовать это с tee:

echo $'line1\n\hi\rhello\rworld' | tee >(awk -F'\r' '' >Outfile) 
Спасибо за это подробное объяснение! Я действительно восхищаюсь теми, кто понимает все эти вещи, связанные с перенаправлением-подоболочками, и знает их синтаксис ... Я попробовал ваш последний пример, и он, кажется, работает лучше, чем sed из-за большого количества символов в такой "строке". sjngm 8 лет назад 1
I think I have to come back on this. I went with your last example and I learned that this somehow buffers the output and writes it all in one step to `Outfile` at the end of the program. Is there a way to enforce writing after each `\n` found? As in "write each line as soon as you have it" to `Outfile`? sjngm 8 лет назад 0
Sometimes, it is tricky to figure out where the troublesome buffer is. For starters, try: `awk -F'\r' '' >outfile` John1024 8 лет назад 1
Yeah, I think that did it. Thanks again :) sjngm 8 лет назад 1
1
Jaakko

Мне удалось решить аналогичную проблему с col (фильтровать обратные переводы строки с ввода) .

java -jar my-jar.jar | tee >(col -pb >/tmp/my-jar.log)

РЕДАКТИРОВАТЬ: Уточненный ответ, чтобы лучше соответствовать вопросу.

В самом деле? Используя это, я не вижу «hello» на экране: `(echo -en" hello \ r "; sleep 2; echo" world ") | col-pb` sjngm 7 лет назад 0
Я думаю, это из-за того, что скобки выполняют весь код внутри них, прежде чем передать его следующему. Если убрать скобки, похоже, что он ведет себя как ожидалось `echo -en" hello \ r "; сон 2; эхо "мир" | col -pb`. Предыдущее также может быть записано в файл путем расширения канала с помощью `tee`, в результате чего в файле журнала появляется просто« мир ». Jaakko 7 лет назад 0
Ну, это то, что код должен был делать. Так что либо вы искали решение какой-то другой проблемы, либо не поняли мой вопрос. sjngm 7 лет назад 0
Я понимаю, что вы имеете в виду, я изменил ответ, чтобы использовать замену процесса bash. Таким образом, вы увидите `hello` в консоли и` world` в файле журнала. Jaakko 7 лет назад 0
Да, это работает :) sjngm 7 лет назад 0