Как удалить и заменить последнюю строку в терминале с помощью bash?


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

конечный результат должен выглядеть так:

$ Elapsed time 5 seconds

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

$ Elapsed time 15 seconds
8 75

8 ответов:

Эхо возврат каретки с \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

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

$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz

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

$ echo -e "abcdefghijklmnopqrstuvwxyz\r3[K0123456789"
0123456789

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

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

прежде чем строка будет написана в первый раз, сделайте

tput sc

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

tput rc
tput ed
echo "your stuff here"

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

метод \033 не работал для меня. Метод \r работает, но на самом деле ничего не стирает, просто помещает курсор в начало строки. Поэтому, если новая строка короче старой, вы можете увидеть оставшийся текст в конце строки. В конце концов tput был лучшим способом пойти. Он имеет другие применения, кроме курсора stuff plus он поставляется предварительно установленным во многих дистрибутивах 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=; while [ $time -ge 0 ]; do
        tput rc; tput el
        printf "" $time
        ((time--))
        sleep 1
    done
    tput rc; tput ed;
}

timeout 10 "Self-destructing in %s"

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

echo -e "Foo\rBar" # Will print "Bar"

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

printf "3[5A"

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

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

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

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

в одной строке кода с echo -ne

for i in {60..1}; do echo -ne "Wait for a minute please: $i\r" && sleep 1; done

или printf

for i in {60..1}; do printf "Wait for a minute please: $i\r" && sleep 1; done

самый простой способ-использовать \r персонаж, я думаю.

недостатком является то, что вы не можете иметь полные строки, так как он очищает только текущую строку.

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

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

echo "\nDone"