Подтвердить что ты не робот

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

Мой bash - script выглядит следующим образом:

echo "Description:"
while [ $finishInput -eq 0 ]; do
read tmp
desc="$desc"$'\n'"$tmp"
if [ -z "$tmp" ]; then
finishInput="1"
fi
done
echo -n "Maintainer:"
read maintainer

Он читает desc var до тех пор, пока не будет пуста. После этого я хочу читать другие вещи.

При выполнении текущего текущего script он выглядит так:

Description:
Line 1
Line 2

Maintainer:

Я хотел бы перезаписать последнюю пустую строку с помощью "Maintainer:".

Я искал решение, но нашел только предложения, похожие на

echo -n "Old line"
echo -e "\r new line"

который остается на линии и перезаписывает его. Это невозможно в моем случае.

4b9b3361

Ответ 1

Просто используйте "\e[1A".

В вашем примере вы удаляете текст в той же строке:

$ echo -n "Old line"; echo -e "\e[0K\r new line"
 new line

Если вы хотите вернуться к предыдущей строке, используйте \e [1A:

$ echo "Old line"; echo -en "\e[1A"; echo -e "\e[0K\r new line"
 new line

Если вы хотите перейти на N строк вверх, используйте \e[<N>A.

Ответ 3

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

Когда вы пишете в терминал, вы перемещаете невидимый курсор, как и в любом текстовом редакторе. При использовании echo, он автоматически заканчивает вывод символом новой строки, который перемещает курсор на следующую строку.

$ echo "Hello" && echo " World"
Hello
 World

Вы можете использовать -n чтобы запретить новую строку, и если после этого вы повторите эхо, он добавит его в конец этой строки.

$ echo -n "Hello" && echo " World"
Hello World

Курсор остается там, где он был, поэтому сам по себе мы не можем использовать -n для перезаписи предыдущей строки, нам нужно переместить курсор влево. Для этого нам нужно дать ему escape-последовательность, которую мы дадим echo знать, что мы будем использовать с -e а затем переместим курсор, предоставив возвратную каретку \r которая помещает курсор в начало строки.

$ echo -n "Hello" && echo -e "\rWorld"
World

Может показаться, что это сработало, но посмотрим, что происходит с

$ echo -n "A longer sentance" && echo -e "\rShort sentance"
Short sentancence

Видишь лишних персонажей? Простое написание над строкой только меняет символы, где мы их написали.

Чтобы исправить это, принятый ответ выше использует escape-символ \e[0K чтобы стереть все после курсора, после того, как курсор переместился влево. то есть \r перейти к началу \e[0K стереть до конца.

$ echo -n "A longer sentance" && echo -e "\r\e[0KShort sentance"
Short sentance

Важно \e для начала escape-последовательности работает в zsh но не в sh и не обязательно в bash, однако \033 работает во всех из них. Если вы хотите, чтобы ваш скрипт работал где угодно, вы должны указать \033

$ echo -n "A longer sentance" && echo -e "\r\033[0KShort sentance"
Short sentance

Но экранирующие символы могут предоставить еще больше полезности. Например, \033[1A перемещает курсор на предыдущую строку, поэтому нам не нужен -n в предыдущем эхо:

$ echo "A longer sentance" && echo -e "\r\033[1A\033[0KShort sentance"
Short sentance

\r перейти к началу \033[1A перейти вверх \033[0K стереть до конца

Наконец, все это немного запутано в моей книге, так что вы можете превратить это в функцию:

overwrite() { echo -e "\r\033[1A\033[[email protected]"; }

Использование [email protected] просто помещает все параметры функции в строку

$ echo Longer sentance && overwrite Short sentence
Short sentence

Надеюсь, что это помогает людям, которые хотят знать немного больше.

Ответ 4

Если вы echo -n "Something" эхо без символа новой строки echo -n "Something", вы можете использовать \r со своим следующим эхом, чтобы переместить "курсор" в начало строки echo -e "\\rOverwrite something".

bash overwrite terminal line

#!/bin/bash

CHECK_MARK="\033[0;32m\xE2\x9C\x94\033[0m"

echo -e "\n\e[4mDoing Things\e[0m"
echo -n "doing thing 1..."
sleep 1
echo -e "\\r${CHECK_MARK} thing 1 done"

Просто знайте, что если ваша новая строка короче вашей старой строки, хвост вашей старой строки все равно будет виден. Обратите внимание, что done.. в GIF выше.

Ответ 5

#!/bin/bash

echo "Description:"
while test -z $finishInput; do
 read -s tmp
 desc="$desc"$'\n'"$tmp"
 if [ -z "$tmp" ]; then
 finishInput=1
 else
    echo $tmp
 fi
 #echo "fi="$finishInput;
done
echo -n "Maintainer:"
read maintainer

Это решение избегает пустой строки, но вход не отражается до завершения строк.

Подсказка: моя версия bash не принимала "[$ finishInput -eq 0]".

Ответ 6

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

while sleep 10s; do 
  echo -n $(script)
  echo -n -e "\e[0K\r"
done

Просто замените команду script своей.