Як змінити вміст рядка на терміналі на відміну від написання нового?


24

Отже, коли ви wgetотримуєте веб-сторінку, вона показує вам рядок стану, який вказував, скільки файлів / файлів завантажено. Це виглядає приблизно так:

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

Однак замість того, щоб писати інший рядок для stdout та додавати ще одну смужку прогресу, він оновлює його, як це:

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

І wgetце не єдиний приклад цього. Наприклад, коли ви щось вставляєте, lessа потім виходите, ваша оригінальна підказка все ще є разом із результатом будь-яких команд, які ви виконували раніше. Це як ніколи не пішов.

Отже, мої запитання полягають у тому, як це називається, як я це реалізую, чи працює він лише за один рядок, і чи можу я це використовувати в C?


5
Рекомендую прочитати BashFAQ 44 . Вам це може бути цікавим.
jw013

Відповіді:


32

Перш за все, ваше запитання не має нічого спільного з bash, а не з терміналом. Термінал відповідає на показ тексту програм і сам bash не має контролю над програмами після їх запуску.

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

  • розташуйте курсор на початку рядка
  • видаліть рядок після цього
  • написати новий рядок

щоб створити панель прогресу.

Більш просунуті послідовності відключення терміналу, як правило, залежать від терміналу, наприклад, працюйте лише з Eterm або xterm. ncurses - це бібліотека програмування, яка створює інтерактивні програми з терміналом, тому вам не доведеться використовувати послідовності втечі.

Як перезаписати існуючий рядок із термінальними послідовностями

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 є послідовності відключення для активації та дезактивації альтернативного буфера екрана, який має той же розмір, що і область відображення вікна. Після активації поточний екран зберігається та замінюється альтернативним екраном. Збереження рядків, прокручених у верхній частині вікна, вимкнено, поки нормальний екран не відновиться. Запис терміна cap (5) для xterm дозволяє візуальному редактору vi (1) перейти на альтернативний екран для редагування та відновити екран при виході. Запис меню, що вискакує, спрощує переключення між звичайним та альтернативним екранами для вирізання та вставки.

http://rosettacode.org/wiki/Terminal_control/Preserve_screen перераховує приклад того, як зробити це самостійно, або через tput, або через деякі послідовності втечі.


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
glenn jackman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.