So zeigen und aktualisieren Sie das Echo in derselben Zeile

111

Ich habe folgendes in Bash (unter 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

Aber ich möchte es so machen, dass das "Echo" das folgende Echo in der nächsten Zeile anzeigt (nicht mit der letzten Echoausgabe verketten, sondern ersetzen), damit es so aussieht, als würde es aktualisiert. Ähnlich wie ein Fortschrittsbalken mit Prozent in derselben Zeile angezeigt wird.

Luis Alvarado
quelle

Antworten:

195

Naja ich habe das nicht richtig gelesen man echo Seite dafür .

echo hatte 2 Optionen, die dies tun könnten, wenn ich ein drittes Escape-Zeichen hinzufügen würde.

Die 2 Optionen sind -nund-e .

-ngibt die nachfolgende Newline nicht aus. Das erspart mir also, jedes Mal, wenn ich etwas wiederhole, eine neue Zeile zu wechseln.

-e erlaubt mir, Backslash-Escape-Symbole zu interpretieren.

Ratet mal, welches Fluchtsymbol ich dafür verwenden möchte : \r. Ja, der Wagenrücklauf würde mich zum Start zurückschicken und es wird visuell so aussehen, als würde ich in derselben Zeile aktualisieren.

Die Echolinie würde also so aussehen:

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

Ich musste dem Fluchtsymbol entkommen, damit Bash es nicht tötete. Deshalb sehen Sie dort 2 \Symbole.

Wie von William erwähnt, printfkann auch ähnliche (und noch umfangreichere) Aufgaben wie diese ausführen.

Luis Alvarado
quelle
12
Nur ein Hinweis für die Zukunft: printf macht genau das Gleiche, ohne Optionen. Der Vorteil ist, dass sich printf im Allgemeinen in jeder Umgebung und jedem Betriebssystem ähnlich verhält, während sich Echo manchmal sehr unterschiedlich verhält. Bei plattformübergreifenden Skripten (oder wenn Sie glauben, dass Sie sich jemals dafür interessieren) ist die Verwendung von printf die beste Vorgehensweise.
William T Froggard
8
printf a; printf bAusgänge ab--- printf a\\r; printf bAusgänge b--- printf a\\r; sleep 1; printf bAusgänge a, dannb
XavierStuvw
64

Wenn ich es gut verstanden habe, können Sie Ihr Echo durch die folgende Zeile ersetzen lassen:

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

Hier ist ein kleines Beispiel, das Sie ausführen können, um das Verhalten zu verstehen:

#!/bin/bash
for pc in $(seq 1 100); do
    echo -ne "$pc%\033[0K\r"
    sleep 1
done
echo
Arutaku
quelle
Es scheint, dass auf zsh das Knicht notwendig ist und tatsächlich als der Buchstabe K
ausgegeben wird
1
Tolles Beispiel - für mich war der Hash-Knall am Start der Schlüssel
Felix Eve
22

Die restlichen Antworten sind ziemlich gut, wollten aber nur einige zusätzliche Informationen hinzufügen, falls jemand hierher kommt und nach einer Lösung sucht, um ein mehrzeiliges Echo zu ersetzen / zu aktualisieren.

Deshalb möchte ich Ihnen allen ein Beispiel geben. Das folgende Skript wurde auf einem CentOS-System ausprobiert und verwendet den Befehl "timedatectl", der im Grunde einige detaillierte Zeitinformationen Ihres Systems druckt.

Ich habe mich für diesen Befehl entschieden, da seine Ausgabe mehrere Zeilen enthält und für das folgende Beispiel perfekt funktioniert:

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

Das obige druckt das Ergebnis von "timedatectl " für immer aus und ersetzt das vorherige Echo durch aktualisierte Ergebnisse.

Ich muss erwähnen, dass dieser Code nur ein Beispiel ist, aber je nach Ihren Anforderungen möglicherweise nicht die beste Lösung für Sie. Ein ähnlicher Befehl, der (zumindest visuell) fast dasselbe tun würde, ist "watch -n 3 timedatectl ".

Aber das ist eine andere Geschichte. :) :)

Hoffentlich hilft das!

Antony Fuentes Artavia
quelle
3

Dies ist unterschiedlich nützlich, bitte versuchen Sie es und ändern Sie es nach Bedarf.

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

Sie können dies versuchen .. Meine eigene Version davon ..

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                  "
Raghu K.
quelle
1

Mein Lieblingsweg heißt do the sleep to 50. Hier muss die iVariable in echo-Anweisungen verwendet werden.

for i in $(seq 1 50); do
  echo -ne "$i%\033[0K\r"
  sleep 50
done
echo "ended"
Stphane
quelle
Das ist schön, aber der Cursor verdeckt das erste Zeichen. Ich denke, einige Leerzeichen im Echo könnten das umgehen.
Marathon