Jak wyświetlić i zaktualizować echo w tej samej linii


112

Mam następujące elementy w Bash (w systemie 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

Ale chciałbym, aby to "echo" pokazywało następujące echo w następnej linii (nie łączy się z ostatnim wyjściem echa, ale zamienia je), aby wyglądało na aktualizację. Podobnie jak pasek postępu z procentami wyświetlałby się w tym samym wierszu.

Odpowiedzi:


196

Cóż, nie przeczytałem poprawnie tej man echostrony.

echo miało 2 opcje, które mogłyby to zrobić, gdybym dodał trzeci znak ucieczki.

Dwie opcje to -ni -e.

-nnie wyświetli końcowego znaku nowej linii. Dzięki temu nie przechodzę do nowej linii za każdym razem, gdy coś powtarzam.

-e pozwoli mi zinterpretować symbole ucieczki z ukośnikiem odwrotnym.

Zgadnij, co ucieczka symbol chcę użyć tego: \r. Tak, powrót karetki odesłałby mnie z powrotem na początek i wizualnie będzie wyglądał, jak aktualizuję w tej samej linii.

Więc linia echa wyglądałaby tak:

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

Musiałem uciec przed symbolem ucieczki, żeby Bash go nie zabił. dlatego widzisz tam 2 \symbole.

Jak wspomniał William, printfmoże również wykonywać podobne (a nawet bardziej rozbudowane) zadania, takie jak to.


12
Tylko uwaga na przyszłość: printf zrobi dokładnie to samo, bez żadnych opcji. Zaletą jest to, że printf ogólnie zachowuje się podobnie w każdym środowisku i systemie operacyjnym, podczas gdy echo może czasami zachowywać się zupełnie inaczej. W przypadku skryptów wieloplatformowych (lub jeśli myślisz, że kiedykolwiek Cię to obchodzi), najlepszym rozwiązaniem jest użycie printf.
William T Froggard

8
printf a; printf bwyjścia ab--- printf a\\r; printf bwyjścia b--- printf a\\r; sleep 1; printf bwyjścia a, a następnieb
XavierStuvw

64

Jeśli dobrze zrozumiałem, możesz go uzyskać, zastępując echo następującym wierszem:

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

Oto mały przykład, który możesz uruchomić, aby zrozumieć jego zachowanie:

#!/bin/bash
for pc in $(seq 1 100); do
    echo -ne "$pc%\033[0K\r"
    sleep 1
done
echo

Wygląda na to, że na zsh Knie jest to konieczne i faktycznie zostaje wyrzucone jako litera K.
mknaf

1
Świetny przykład - dla mnie huk na początku był kluczowy
Felix Eve

23

Reszta odpowiedzi jest całkiem dobra, ale chciałem tylko dodać dodatkowe informacje na wypadek, gdyby ktoś przyszedł tutaj, szukając rozwiązania zastępującego / aktualizującego echo wielowierszowe.

Chciałbym więc podzielić się z wami przykładem. Poniższy skrypt został wypróbowany w systemie CentOS i używa polecenia „timedatectl”, które zasadniczo drukuje szczegółowe informacje o czasie w systemie.

Zdecydowałem się użyć tego polecenia, ponieważ jego wyjście zawiera wiele wierszy i działa idealnie w poniższym przykładzie:

#!/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

Powyższe wypisze wynik „ timedatectl” na zawsze i zastąpi poprzednie echo zaktualizowanymi wynikami.

Muszę wspomnieć, że ten kod to tylko przykład, ale może nie jest dla Ciebie najlepszym rozwiązaniem w zależności od Twoich potrzeb. Podobnym poleceniem, które zrobiłoby prawie to samo (przynajmniej wizualnie), jest „ watch -n 3 timedatectl”.

Ale to inna historia. :)

Mam nadzieję, że to pomoże!


3

Jest to bardzo przydatne, wypróbuj je i zmień w razie potrzeby.

#! bin/bash
for load in $(seq 1 100); do
    echo -ne "$load % downloded ...\r"
    sleep 1
done
echo "100"
echo "Loaded ..."

3

Możesz spróbować… Moja własna wersja…

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

Mój ulubiony sposób to zrobić sen do 50. Tutaj izmienna musi być używana w instrukcjach echo.

for i in $(seq 1 50); do
  echo -ne "$i%\033[0K\r"
  sleep 50
done
echo "ended"

to fajne, ale kursor przesłania pierwszy znak. Myślę, że niektóre przestrzenie w echu mogą to obejść.
maraton
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.