Как удалить и заменить последнюю строку в терминале с помощью bash? - PullRequest
82 голосов
/ 05 марта 2010

Я хочу реализовать индикатор выполнения, показывающий прошедшие секунды в bash.Для этого мне нужно стереть последнюю строку, показанную на экране (команда «очистить» стирает весь экран, но мне нужно стереть только строку индикатора выполнения и заменить ее новой информацией).* Окончательный результат должен выглядеть следующим образом:

$ Elapsed time 5 seconds

Затем через 10 секунд я хочу заменить это предложение (в той же позиции на экране) на:

$ Elapsed time 15 seconds

Ответы [ 8 ]

170 голосов
/ 21 июля 2011

Возврат каретки сам по себе только перемещает курсор в начало строки. Это нормально, если каждая новая строка вывода имеет длину по крайней мере такую ​​же, как и предыдущая, но если новая строка короче, предыдущая строка не будет полностью перезаписана, например ::100100

$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz

Чтобы на самом деле очистить строку для нового текста, вы можете добавить \033[K после \r:

$ echo -e "abcdefghijklmnopqrstuvwxyz\r\033[K0123456789"
0123456789

http://en.wikipedia.org/wiki/ANSI_escape_code

104 голосов
/ 05 марта 2010

эхо возврата каретки с \ r

seq 1 1000000 | while read i; do echo -en "\r$i"; done

от мужского эха:

-n     do not output the trailing newline
-e     enable interpretation of backslash escapes

\r     carriage return
17 голосов
/ 20 сентября 2013

Ответ Дерека Вейта работает хорошо, если длина линии никогда не превышает ширину терминала. Если это не так, следующий код предотвратит вывод нежелательной почты:

перед первой записью строки, выполните

tput sc

, который сохраняет текущую позицию курсора. Теперь, когда вы хотите напечатать свою строку, используйте

tput rc
tput ed
echo "your stuff here"

, чтобы сначала вернуться в сохраненную позицию курсора, затем очистить экран от курсора до дна и, наконец, записать вывод.

11 голосов
/ 14 января 2015

Метод \ 033 у меня не сработал. Метод \ r работает, но на самом деле он ничего не стирает, просто помещает курсор в начало строки. Поэтому, если новая строка короче старой, вы можете увидеть оставшийся текст в конце строки. В конце концов, tput был лучшим способом. У него есть и другие применения, кроме курсора, плюс он предустановлен во многих дистрибутивах Linux и BSD, поэтому должен быть доступен для большинства пользователей bash.

#/bin/bash
tput sc # save cursor
printf "Something that I made up for this string"
sleep 1
tput rc;tput el # rc = restore cursor, el = erase to end of line
printf "Another message for testing"
sleep 1
tput rc;tput el
printf "Yet another one"
sleep 1
tput rc;tput el

Вот небольшой скрипт обратного отсчета для игры:

#!/bin/bash
timeout () {
    tput sc
    time=$1; while [ $time -ge 0 ]; do
        tput rc; tput el
        printf "$2" $time
        ((time--))
        sleep 1
    done
    tput rc; tput ed;
}

timeout 10 "Self-destructing in %s"
5 голосов
/ 20 мая 2017

Если результат выполнения многострочный, или сценарий уже напечатал бы символ новой строки, вы можете перескочить строки с чем-то вроде:

printf "\033[5A"

, который заставит курсор подскочить на 5 строк. Затем вы можете перезаписать все, что вам нужно.

Если это не сработает, вы можете попробовать printf "\e[5A" или echo -e "\033[5A", что должно иметь тот же эффект.

По сути, с помощью escape-последовательностей вы можете контролировать практически все на экране.

4 голосов
/ 05 марта 2010

Используйте символ возврата каретки:

echo -e "Foo\rBar" # Will print "Bar"
1 голос
/ 27 сентября 2018

Достигнуть этого можно, поместив возврат каретки \r.

В одну строку кода с printf

for i in {10..1}; do printf "Counting down: $i\r" && sleep 1; done

или с echo -ne

for i in {10..1}; do echo -ne "Counting down: $i\r" && sleep 1; done
0 голосов
/ 05 марта 2010

Самый простой способ - использовать, наверное, символ \r.

Недостаток в том, что у вас не может быть завершенных строк, поскольку он только очищает текущую строку.

Простой пример:

time=5
echo -n "Elapsed $time seconds"
sleep 10
time=15
echo -n "Elapsed $time seconds"

echo "\nDone"
...