Как показать и обновить эхо в одной строке

113

У меня в Bash (в Linux) есть следующее

for dir in Movies/*
do
  (cd "$dir" && pwd|cut -d \/ -f5|tr -s '\n' ', ' >> ../../movielist &&
  exiftool * -t -s3 -ImageSize -FileType|tr -s '\t' ',' >> ../../movielist )
echo "Movie $movies - $dir ADDED!"
let movies=movies+1
done

Но я хочу сделать так, чтобы «эхо» показывало следующее эхо в следующей строке (не объединять с последним выводом эха, а заменять его), чтобы оно выглядело так, как будто оно обновляется. Подобно тому, как индикатор выполнения с процентами отображается в той же строке.

Луис Альварадо
источник

Ответы:

197

Ну я не правильно прочитал man echoстраницу для этого.

У echo было 2 варианта, которые могли бы сделать это, если бы я добавил 3-й escape-символ.

Есть 2 варианта: -nи -e.

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

-e позволит мне интерпретировать escape-символы с обратной косой чертой.

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

Итак, эхо-линия будет выглядеть так:

echo -ne "Movie $movies - $dir ADDED!"\\r

Мне пришлось избегать символа побега, чтобы Баш не убил его. вот почему вы видите 2\ символа.

Как упоминал Уильям, он printfтакже может выполнять аналогичные (и даже более обширные) задачи, подобные этой.

Луис Альварадо
источник
12
Замечание на будущее: printf будет делать то же самое, без каких-либо опций. Преимущество в том, что printf обычно ведет себя одинаково в каждой среде и ОС, в то время как echo иногда может вести себя по-разному. Для кроссплатформенных скриптов (или, если вы думаете, что это может вас когда-нибудь заинтересовать) лучше всего использовать printf.
Уильям Т. Фроггард
8
printf a; printf bвыходы ab--- printf a\\r; printf bвыходы b--- printf a\\r; sleep 1; printf bвыходы a, затемb
XavierStuvw
64

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

echo -ne "Movie $movies - $dir ADDED! \033[0K\r"

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

#!/bin/bash
for pc in $(seq 1 100); do
    echo -ne "$pc%\033[0K\r"
    sleep 1
done
echo
Arutaku
источник
Похоже, что на zsh в Kэтом нет необходимости и фактически
выводится
1
Отличный пример - для меня ключевым моментом был хэш-бэнг в начале
Felix Eve
23

Остальные ответы довольно хороши, но просто хотел добавить дополнительную информацию на случай, если кто-то придет сюда в поисках решения для замены / обновления многострочного эха.

Итак, я хотел бы поделиться со всеми вами примером. Следующий сценарий был опробован в системе CentOS и использует команду «timedatectl», которая в основном выводит некоторую подробную информацию о времени вашей системы.

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

#!/bin/bash
while true; do
  COMMAND=$(timedatectl) #Save command result in a var.
  echo "$COMMAND" #Print command result, including new lines.

  sleep 3 #Keep above's output on screen during 3 seconds before clearing it

  #Following code clears previously printed lines
  LINES=$(echo "$COMMAND" | wc -l) #Calculate number of lines for the output previously printed
  for (( i=1; i <= $(($LINES)); i++ ));do #For each line printed as a result of "timedatectl"
    tput cuu1 #Move cursor up by one line
    tput el #Clear the line
  done

done

Вышеупомянутое напечатает результат "timedatectl " навсегда и заменит предыдущее эхо обновленными результатами.

Я должен упомянуть, что этот код является только примером, но, возможно, не лучшим решением для вас в зависимости от ваших потребностей. Похожая команда, которая будет делать почти то же самое (по крайней мере, визуально): "watch -n 3 timedatectl ».

Но это другая история. :)

Надеюсь, это поможет!

Энтони Фуэнтес Артавиа
источник
3

Это может быть полезно, попробуйте и при необходимости измените.

#! bin/bash
for load in $(seq 1 100); do
    echo -ne "$load % downloded ...\r"
    sleep 1
done
echo "100"
echo "Loaded ..."
Манту
источник
3

Вы можете попробовать это .. Моя собственная версия ..

funcc() {
while true ; do 
for i in \| \/ \- \\ \| \/ \- \\; do 
  echo -n -e "\r$1  $i  "
sleep 0.5
done  
#echo -e "\r                                                                                      "
[ -f /tmp/print-stat ] && break 2
done
}

funcc "Checking Kubectl" & &>/dev/null
sleep 5
touch /tmp/print-stat
echo -e "\rPrint Success                  "
Рагху К.
источник
1

Мой любимый способ - уснуть до 50. Здесь iпеременную нужно использовать внутри эхо-операторов.

for i in $(seq 1 50); do
  echo -ne "$i%\033[0K\r"
  sleep 50
done
echo "ended"
Стфан
источник
это хорошо, но курсор закрывает первый символ. Думаю, некоторые пробелы в эхо могут обойти это.
марафон