Как изменить содержимое строки на терминале, в отличие от написания новой?

24

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

25%[=============>______________________________________] 25,000 100.0K/s (подчеркивания - пробелы; я просто не могу понять, как получить более одного последовательного пробела)

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

50%[===========================>________________________] 50,000 100.0K/s

И wgetэто не единственный пример этого. Например, когда вы отправляете что-то в lessи затем выходите, ваше исходное приглашение все еще там, вместе с результатом любых команд, которые вы выполняли ранее. Как будто ты никогда не уходил.

Итак, мои вопросы: как это называется, как мне это реализовать, работает ли это только для одной строки за раз, и могу ли я использовать это в C?

fouric
источник
5
Я рекомендую прочитать BashFAQ 44 . Вы можете найти это интересным.
jw013
6
Рекомендуемое прочтение: какова точная разница между терминалом, оболочкой, tty и консолью?
Жиль "ТАК - перестань быть злым"

Ответы:

32

Прежде всего, ваш вопрос не имеет ничего общего с bash, а с терминалом. Терминал отвечает за отображение текста программ, а сам bash не контролирует программы после их запуска.

Терминалы предлагают последовательности управления для управления цветом, шрифтом, положением курсора и многим другим. Для получения списка стандартизированных терминальных последовательностей посмотрите на http://www.termsys.demon.co.uk/vtansi.htm. Вы можете, например,

  • поместите курсор в начало строки
  • удалить строку потом
  • написать новую строку

создать индикатор выполнения.

Более продвинутые escape-последовательности терминала обычно зависят от терминала, например, работают только с Eterm или xterm. ncurses - это библиотека программирования, которая позволяет создавать интерактивные программы с помощью терминала, чтобы вам не приходилось использовать escape-последовательности.

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

echo long text
sleep 1
printf "\033[1A"  # move cursor one line up
printf "\033[K"   # delete till end of line
echo foo

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

Одно простое решение - не писать новую строку в конце, а записывать возврат каретки, который в основном сбрасывает курсор в начало строки, например:

echo -n first 
sleep 1 
echo -ne "\rsecond"
echo

\rИли возврат каретки будет поместить курсор в начало строки и позволяет перезаписать содержимое строки.

Переключаться между буферами как lessилиvi

Поведение lessтакже связано с более продвинутой функцией терминала, альтернативным экраном:

В режиме VT102 существуют escape-последовательности для активации и деактивации альтернативного экранного буфера, размер которого совпадает с размером области отображения окна. При активации текущий экран сохраняется и заменяется альтернативным экраном. Сохранение строк, прокручиваемых в верхней части окна, отключено до восстановления нормального экрана. Запись term-cap (5) для xterm позволяет визуальному редактору vi (1) переключаться на альтернативный экран для редактирования и восстанавливать экран при выходе. Пункт всплывающего меню позволяет легко переключаться между обычным и альтернативным экранами для вырезания и вставки.

В http://rosettacode.org/wiki/Terminal_control/Preserve_screen приведен пример того, как сделать это самостоятельно, через tput или через некоторые escape-последовательности.

Ульрих Дангел
источник
15

Вместо использования echoкоторого автоматически добавляется новая строка в строку, используйте printf "%s\r" whatever- возврат каретки отправляет курсор в начало текущей строки. пример:

seq 1 15 | while read num; do printf "%2d\r" $num; sleep 1; done; echo ""
Гленн Джекман
источник
в зависимости от курсора вашего терминала, это может быть более приятнымprintf "\r%2d " $num
Гленн Джекман