Wenn Sie in Bash oder einer anderen Shell in * NIX Skripte erstellen und einen Befehl ausführen, der länger als einige Sekunden dauert, wird ein Fortschrittsbalken benötigt.
Beispiel: Kopieren einer großen Datei, Öffnen einer großen TAR-Datei.
Welche Möglichkeiten empfehlen Sie, Shell-Skripten Fortschrittsbalken hinzuzufügen?
Antworten:
Sie können dies implementieren, indem Sie eine Zeile überschreiben. Verwenden Sie
\r
diese Option , um zum Zeilenanfang zurückzukehren, ohne\n
auf das Terminal zu schreiben .Schreiben Sie,
\n
wenn Sie fertig sind, um die Zeile voranzutreiben.Verwenden Sie,
echo -ne
um:\n
und\r
.Hier ist eine Demo:
In einem Kommentar unten erwähnt puk, dass dies "fehlschlägt", wenn Sie mit einer langen Zeile beginnen und dann eine kurze Zeile schreiben möchten: In diesem Fall müssen Sie die Länge der langen Zeile überschreiben (z. B. mit Leerzeichen).
quelle
printf
anstelle vonecho
.printf "#### (50%%)\r"
, es würde nicht mit einfachen Anführungszeichen funktionieren und Prozentzeichen müssen maskiert werden.Vielleicht interessiert Sie auch, wie man einen Spinner macht :
Kann ich in Bash einen Spinner machen?
quelle
while :;do for s in / - \\ \|; do printf "\r$s";sleep .1;done;done
(*:sleep
erfordert möglicherweise eher Ints als Dezimalstellen)some_work ...
obigen Zeile; Eine ausführlichere Diskussion, die auf dieser hilfreichen Antwort aufbaut, und Adam Katz 'hilfreicher Kommentar - mit Schwerpunkt auf der POSIX-Konformität - finden Sie hier .\b
eher auf als basieren\r
, da er sonst nur am Anfang einer Zeile funktioniert:while :; do for c in / - \\ \|; do printf '%s\b' "$c"; sleep 1; done; done
- oder, wenn der Cursor hinter dem Spinner angezeigt wird ist unerwünscht:printf ' ' && while :; do for c in / - \\ \|; do printf '\b%s' "$c"; sleep 1; done; done
job=$!
) speichern und dann ausführenwhile kill -0 $job 2>/dev/null;do …
, zum Beispiel:sleep 15 & job=$!; while kill -0 $job 2>/dev/null; do for s in / - \\ \|; do printf "\r$s"; sleep .1; done; done
Einige Beiträge haben gezeigt, wie der Fortschritt des Befehls angezeigt wird. Um es zu berechnen, müssen Sie sehen, wie weit Sie fortgeschritten sind. Auf BSD-Systemen akzeptieren einige Befehle, wie z. B. dd (1), ein
SIGINFO
Signal und melden ihren Fortschritt. Auf Linux-Systemen reagieren einige Befehle ähnlichSIGUSR1
. Wenn diese Funktion verfügbar ist, können Sie Ihre Eingabe weiterleitendd
, um die Anzahl der verarbeiteten Bytes zu überwachen.Alternativ können Sie
lsof
den Versatz des Lesezeigers der Datei ermitteln und damit den Fortschritt berechnen. Ich habe einen Befehl namens pmonitor geschrieben , der den Fortschritt der Verarbeitung eines bestimmten Prozesses oder einer bestimmten Datei anzeigt. Damit können Sie Dinge wie die folgenden tun.Eine frühere Version von Linux- und FreeBSD-Shell-Skripten wird in meinem Blog angezeigt .
quelle
awk
ins Spiel kommt!Ich habe eine einfache Fortschrittsbalkenfunktion, die ich neulich geschrieben habe:
Oder schnappen Sie es sich unter
https://github.com/fearside/ProgressBar/
quelle
printf "\rProgress : [${_fill// /▇}${_empty// / }] ${_progress}%%"
Verwenden Sie den Linux-Befehl pv:
http://linux.die.net/man/1/pv
Es kennt die Größe nicht, wenn es sich in der Mitte des Streams befindet, aber es gibt eine Geschwindigkeit und eine Gesamtmenge an. Von dort aus können Sie herausfinden, wie lange es dauern sollte, und Feedback erhalten, damit Sie wissen, dass es nicht hängen geblieben ist.
quelle
Ich suchte nach etwas Sexyem als der ausgewählten Antwort, ebenso wie mein eigenes Skript.
Vorschau
Quelle
Ich habe es auf Github gelegt
progress-bar.sh
Verwendungszweck
quelle
progress-bar 100
GNU tar verfügt über eine nützliche Option, die die Funktionalität eines einfachen Fortschrittsbalkens bietet.
(...) Eine weitere verfügbare Checkpoint-Aktion ist 'dot' (oder '.'). Es weist tar an, einen einzelnen Punkt auf dem Standard-Listing-Stream zu drucken, z.
Der gleiche Effekt kann erzielt werden durch:
quelle
--checkpoint=.10
. Es funktioniert auch gut beim Extrahieren mittar -xz
.Eine einfachere Methode, die auf meinem System mit dem Dienstprogramm pipeview (pv) funktioniert.
quelle
Ich habe nichts Ähnliches gesehen und alle benutzerdefinierten Funktionen hier scheinen sich auf das Rendern allein zu konzentrieren. Meine sehr einfache POSIX-kompatible Lösung unten mit schrittweisen Erklärungen, da diese Frage nicht trivial ist.
TL; DR
Das Rendern des Fortschrittsbalkens ist sehr einfach. Die Schätzung, wie viel davon gerendert werden soll, ist eine andere Sache. So rendern (animieren) Sie den Fortschrittsbalken - Sie können dieses Beispiel kopieren und in eine Datei einfügen und ausführen:
{1..20}
- Werte von 1 bis 20echo -n
- am Ende ohne neue Zeile druckenecho -e
- beim Drucken Sonderzeichen interpretieren"\r"
- Wagenrücklauf, ein Sonderzeichen, um zum Zeilenanfang zurückzukehrenSie können dafür sorgen, dass jeder Inhalt mit jeder Geschwindigkeit gerendert wird, sodass diese Methode sehr universell ist, z. B. häufig zur Visualisierung von "Hacking" in albernen Filmen verwendet wird, kein Scherz.
Vollständige Antwort
Das Problem besteht darin, wie der
$i
Wert bestimmt wird, dh wie viel des Fortschrittsbalkens angezeigt werden soll. Im obigen Beispiel habe ich es nur in einerfor
Schleife inkrementieren lassen , um das Prinzip zu veranschaulichen, aber eine reale Anwendung würde eine Endlosschleife verwenden und die$i
Variable bei jeder Iteration berechnen . Für diese Berechnung werden die folgenden Zutaten benötigt:Falls
cp
es die Größe einer Quelldatei und die Größe der Zieldatei benötigt:stat
- Überprüfen Sie die Dateistatistiken-c
- formatierten Wert zurückgeben%s
- GesamtgrößeBei Vorgängen wie dem Entpacken von Dateien ist die Berechnung der Quellgröße etwas schwieriger, aber immer noch so einfach wie das Abrufen der Größe einer unkomprimierten Datei:
gzip -l
- Informationen zum Zip-Archiv anzeigentail -n1
- mit 1 Zeile von unten arbeitentr -s ' '
- mehrere Leerzeichen in eines übersetzen (zusammendrücken)cut -d' ' -f3
- 3. durch Leerzeichen getrennte Spalte ausschneidenHier ist jedoch das Fleisch des Problems. Diese Lösung ist immer weniger allgemein. Alle Berechnungen des tatsächlichen Fortschritts sind eng an die Domäne gebunden, die Sie visualisieren möchten. Ist es sich um eine einzelne Dateioperation, einen Timer-Countdown, eine steigende Anzahl von Dateien in einem Verzeichnis, eine Operation für mehrere Dateien usw. handelt? kann nicht wiederverwendet werden. Der einzige wiederverwendbare Teil ist das Rendern des Fortschrittsbalkens. Um es wiederzuverwenden, müssen Sie es abstrahieren und in einer Datei speichern (z. B.
/usr/lib/progress_bar.sh
) und dann Funktionen definieren, die domänenspezifische Eingabewerte berechnen. So könnte ein verallgemeinerter Code aussehen (ich habe auch die$BAR
Dynamik erzeugt, weil die Leute danach gefragt haben, der Rest sollte jetzt klar sein):printf
- eine integrierte Funktion zum Drucken von Inhalten in einem bestimmten Formatprintf '%50s'
- nichts drucken, mit 50 Leerzeichen auffüllentr ' ' '#'
- Übersetzen Sie jedes Leerzeichen in ein Hash-ZeichenUnd so würden Sie es verwenden:
Offensichtlich kann es in eine Funktion eingewickelt, umgeschrieben werden, um mit Pipeline-Streams zu arbeiten, umgeschrieben in eine andere Sprache, was auch immer Ihr Gift ist.
quelle
Ich möchte auch meinen eigenen Fortschrittsbalken beisteuern
Durch die Verwendung von Half-Unicode-Blöcken wird die Genauigkeit von Unterzeichen erreicht
Code ist enthalten
quelle
Fortschrittsbalken im APT-Stil (unterbricht die normale Ausgabe nicht)
BEARBEITEN: Eine aktualisierte Version finden Sie auf meiner Github-Seite
Ich war mit den Antworten auf diese Frage nicht zufrieden. Was ich persönlich gesucht habe, war ein ausgefallener Fortschrittsbalken, wie APT sieht.
Ich habe mir den C-Quellcode für APT angesehen und beschlossen, mein eigenes Äquivalent für Bash zu schreiben.
Dieser Fortschrittsbalken bleibt gut am unteren Rand des Terminals und stört keine an das Terminal gesendeten Ausgaben.
Bitte beachten Sie, dass die Leiste derzeit auf 100 Zeichen Breite festgelegt ist. Wenn Sie es auf die Größe des Terminals skalieren möchten, ist dies ebenfalls recht einfach (die aktualisierte Version auf meiner Github-Seite behandelt dies gut).
Ich werde mein Skript hier veröffentlichen. Anwendungsbeispiel:
Das Skript (ich empfehle dringend die Version auf meinem Github):
quelle
Auf diese Weise können Sie sich vorstellen, dass ein Befehl noch ausgeführt wird:
Dadurch wird eine Endlos-while-Schleife erstellt , die im Hintergrund ausgeführt wird und ein "" wiedergibt. jede Sekunde. Dies wird
.
in der Shell angezeigt . Führen Sie dentar
Befehl oder einen beliebigen Befehl aus. Wenn dass beendet Befehl ausgeführt wird dann töten den letzten Job im Hintergrund laufen - was das ist unendlich while - Schleife .quelle
So könnte es aussehen
Hochladen einer Datei
Warten auf den Abschluss eines Auftrags
Einfache Funktion, die es implementiert
Sie können es einfach kopieren und in Ihr Skript einfügen. Es erfordert nichts anderes, um zu funktionieren.
Anwendungsbeispiel
Hier laden wir eine Datei hoch und zeichnen den Fortschrittsbalken bei jeder Iteration neu. Es spielt keine Rolle, welcher Job tatsächlich ausgeführt wird, solange wir zwei Werte erhalten können: Maximalwert und aktueller Wert.
Im folgenden Beispiel ist der Maximalwert
file_size
und der aktuelle Wert wird von einer Funktion geliefert und aufgerufenuploaded_bytes
.quelle
Die meisten Unix-Befehle geben Ihnen nicht die Art von direktem Feedback, von dem Sie dies tun können. Einige geben Ihnen eine Ausgabe auf stdout oder stderr, die Sie verwenden können.
Für so etwas wie tar können Sie den Schalter -v verwenden und die Ausgabe an ein Programm weiterleiten, das für jede gelesene Zeile eine kleine Animation aktualisiert. Während tar eine Liste der entpackten Dateien schreibt, kann das Programm die Animation aktualisieren. Um einen Prozentsatz zu vervollständigen, müssten Sie die Anzahl der Dateien kennen und die Zeilen zählen.
cp gibt diese Art von Ausgabe meines Wissens nicht aus. Um den Fortschritt von cp zu überwachen, müssten Sie die Quell- und Zieldateien überwachen und die Größe des Ziels überwachen. Sie können ein kleines c-Programm mit dem Systemaufruf stat (2) schreiben , um die Dateigröße zu ermitteln. Dies würde die Größe der Quelle lesen, dann die Zieldatei abfragen und einen% vollständigen Balken basierend auf der Größe der bisher geschriebenen Datei aktualisieren.
quelle
Meine Lösung zeigt den Prozentsatz des Tarballs an, der gerade unkomprimiert und geschrieben wird. Ich benutze dies beim Schreiben von 2 GB Root-Dateisystem-Images. Sie brauchen wirklich einen Fortschrittsbalken für diese Dinge. Was ich tue, ist zu verwenden
gzip --list
, um die gesamte unkomprimierte Größe des Tarballs zu erhalten. Daraus berechne ich den Blockierungsfaktor, der benötigt wird, um die Datei in 100 Teile zu teilen. Schließlich drucke ich für jeden Block eine Prüfpunktnachricht. Für eine 2-GB-Datei ergibt dies etwa 10 MB pro Block. Wenn das zu groß ist, können Sie den BLOCKING_FACTOR durch 10 oder 100 teilen, aber dann ist es schwieriger, eine hübsche Ausgabe in Prozent zu drucken.Angenommen, Sie verwenden Bash, können Sie die folgende Shell-Funktion verwenden
quelle
Erstens ist der Balken nicht der einzige Rohrfortschrittsmesser. Der andere (vielleicht sogar noch bekanntere) ist pv (Pipe Viewer).
Zweitens können bar und pv zum Beispiel so verwendet werden:
oder auch:
Ein nützlicher Trick, wenn Sie bar und pv in Befehlen verwenden möchten, die mit Dateien arbeiten, die in Argumenten angegeben sind, z. B. copy file1 file2, ist die Verwendung der Prozessersetzung :
Die Prozessersetzung ist eine magische Sache, die temporäre FIFO-Pipe-Dateien / dev / fd / erstellt und stdout aus dem ausgeführten Prozess (in Klammern) über diese Pipe verbindet, und die Kopie sieht sie wie eine normale Datei aus (mit einer Ausnahme kann sie nur gelesen werden) vorwärts).
Aktualisieren:
Der Befehl bar selbst ermöglicht auch das Kopieren. After Man Bar:
Aber Prozesssubstitution ist meiner Meinung nach eine allgemeinere Methode, um dies zu tun. Und es verwendet das CP-Programm selbst.
quelle
Ich bevorzuge den Dialog mit dem Parameter --gauge. Wird sehr häufig in .deb-Paketinstallationen und anderen grundlegenden Konfigurationsmaterialien vieler Distributionen verwendet. Sie müssen das Rad also nicht neu erfinden
Geben Sie einfach einen int-Wert von 1 bis 100 @stdin ein. Ein einfaches und albernes Beispiel:
Ich habe diese / bin / Wait- Datei (mit chmod u + x perms) zum Kochen: P.
Also kann ich sagen:
Wait "34 min" "warm up the oven"
oder
Wait "dec 31" "happy new year"
quelle
Für mich ist das Kommando am einfachsten zu bedienen und am besten auszusehen,
pv
oderbar
wie ein Typ bereits geschrieben hatBeispiel: Sie müssen eine Sicherungskopie des gesamten Laufwerks mit erstellen
dd
normalerweise benutzt du
dd if="$input_drive_path" of="$output_file_path"
mit
pv
dir kannst du es so machen:dd if="$input_drive_path" | pv | dd of="$output_file_path"
und der Fortschritt geht direkt
STDOUT
wie folgt vor:Nachdem dies erledigt ist, wird eine Zusammenfassung angezeigt
quelle
pv
oderbar
visualisieren, z. B. den Countdown des Timers, die Position in einer Textdatei, die Installation Ihrer App, die Einrichtung der Laufzeit usw.?Viele Antworten beschreiben das Schreiben eigener Befehle zum Ausdrucken
'\r' + $some_sort_of_progress_msg
. Das Problem ist manchmal, dass das Ausdrucken von Hunderten dieser Updates pro Sekunde den Prozess verlangsamt.Wenn jedoch einer Ihrer Prozesse eine Ausgabe erzeugt (z. B.
7z a -r newZipFile myFolder
wird jeder Dateiname beim Komprimieren ausgegeben), gibt es eine einfachere, schnellere, schmerzlosere und anpassbare Lösung.Installieren Sie das Python-Modul
tqdm
.Hilfe :
tqdm -h
. Ein Beispiel mit mehr Optionen:Als Bonus können Sie
tqdm
Iterables auch in Python-Code einschließen.https://github.com/tqdm/tqdm/blob/master/README.rst#module
quelle
tqdm
STDOUTwc -l
durch ein Rohr zu leiten . Sie wollen dem wahrscheinlich entkommen.tqdm
zeigt den Fortschritt an,STDERR
während die EingabeSTDIN
an weitergeleitet wirdSTDOUT
. In diesem Fallwc -l
würde dieselbe Eingabe empfangen, als wäre sietqdm
nicht enthalten.Basierend auf der Arbeit von Edouard Lopez habe ich einen Fortschrittsbalken erstellt, der der Größe des Bildschirms entspricht, unabhängig davon, um welchen es sich handelt. Hör zu.
Es ist auch auf Git Hub veröffentlicht .
Genießen
quelle
https://github.com/extensionsapp/progre.sh
40 Prozent Fortschritt schaffen:
progreSh 40
quelle
Dies gilt nur mit Gnome Zenity. Zenity bietet eine großartige native Oberfläche für Bash-Skripte: https://help.gnome.org/users/zenity/stable/
Aus dem Zenity Progress Bar Beispiel:
quelle
Ich habe eine Antwort aus Erstellen einer Zeichenfolge wiederholter Zeichen im Shell-Skript zum Wiederholen von Zeichen verwendet . Ich habe zwei relativ kleine Bash- Versionen für Skripte, die einen Fortschrittsbalken anzeigen müssen (zum Beispiel eine Schleife, die viele Dateien durchläuft, aber für große TAR-Dateien oder Kopiervorgänge nicht nützlich ist). Die schnellere besteht aus zwei Funktionen, eine zum Vorbereiten der Zeichenfolgen für die Balkenanzeige:
und eine, um einen Fortschrittsbalken anzuzeigen:
Es könnte verwendet werden als:
Dies bedeutet, dass Sie Zeichenfolgen für Balken mit 50 "#" Zeichen vorbereiten und danach:
zeigt die Anzahl der "#" Zeichen an, die dem Verhältnis 35/80 entsprechen:
Beachten Sie, dass die Funktion die Leiste immer wieder in derselben Zeile anzeigt, bis Sie (oder ein anderes Programm) eine neue Zeile drucken. Wenn Sie -1 als ersten Parameter eingeben, wird der Balken gelöscht:
Die langsamere Version ist alles in einer Funktion:
und es kann verwendet werden als (das gleiche Beispiel wie oben):
Wenn Sie einen Fortschrittsbalken für stderr benötigen, fügen Sie ihn einfach
>&2
am Ende jedes printf-Befehls hinzu.quelle
Versuchen Sie die folgenden Befehle, um den Fortschritt der Aktivität anzuzeigen:
ODER
ODER
ODER
Man kann Flags / Variablen innerhalb der while-Schleife verwenden, um den Wert / das Ausmaß des Fortschritts zu überprüfen und anzuzeigen.
quelle
Mit den oben aufgeführten Vorschlägen habe ich beschlossen, meinen eigenen Fortschrittsbalken zu implementieren.
quelle
percent_none="$(( 100 - "$percent_done" ))"
zumpercent_none="$(( 100 - $percent_done))"
Ich habe eine reine Shell-Version für ein eingebettetes System erstellt und dabei Folgendes genutzt:
Die SIGUSR1-Signalverarbeitungsfunktion von / usr / bin / dd.
Wenn Sie ein 'kill SIGUSR1 $ (pid_of_running_dd_process)' senden, wird grundsätzlich eine Zusammenfassung der Durchsatzgeschwindigkeit und des übertragenen Betrags ausgegeben.
dd hinterlegen und dann regelmäßig nach Updates abfragen und Hash-Ticks generieren, wie es früher bei FTP-Clients der alten Schule der Fall war.
Verwenden von / dev / stdout als Ziel für nicht stdout-freundliche Programme wie scp
Mit dem Endergebnis können Sie jede Dateiübertragungsoperation ausführen und eine Fortschrittsaktualisierung erhalten, die wie eine FTP-Hash-Ausgabe der alten Schule aussieht, bei der Sie nur für jedes X-Byte eine Hash-Markierung erhalten.
Dies ist kaum Produktionsqualitätscode, aber Sie bekommen die Idee. Ich denke, es ist süß.
Für das, was es wert ist, spiegelt sich die tatsächliche Anzahl der Bytes möglicherweise nicht richtig in der Anzahl der Hashes wider - je nach Rundungsproblemen haben Sie möglicherweise mehr oder weniger. Verwenden Sie dies nicht als Teil eines Testskripts, es ist nur eine Augenweide. Und ja, ich bin mir bewusst, dass dies furchtbar ineffizient ist - es ist ein Shell-Skript und ich entschuldige mich nicht dafür.
Beispiele mit wget, scp und tftp am Ende. Es sollte mit allem funktionieren, was Daten ausgibt. Stellen Sie sicher, dass Sie / dev / stdout für Programme verwenden, die nicht stdout-freundlich sind.
Beispiele:
quelle
pidof dd
beängstigend ist.$!
ausdd
und warten auf[[ -e /proc/${DD_PID} ]]
.Falls Sie einen zeitlichen Fortschrittsbalken anzeigen müssen (indem Sie die Anzeigezeit im Voraus kennen), können Sie Python wie folgt verwenden:
Angenommen, Sie haben das Python-Skript als gespeichert
progressbar.py
, können Sie den Fortschrittsbalken Ihres Bash-Skripts anzeigen, indem Sie den folgenden Befehl ausführen:Es würde
50
Zeichen in der Größe eines Fortschrittsbalkens anzeigen und für10
Sekunden "laufen" .quelle
Ich habe auf der Antwort von Fearside aufgebaut
Dadurch wird eine Verbindung zu einer Oracle-Datenbank hergestellt, um den Fortschritt einer RMAN-Wiederherstellung abzurufen.
quelle
könnte eine Funktion erstellen, die dies auf einer Skala von 1 bis 10 für die Anzahl der Balken zeichnet:
quelle
Ausgabe:
Hinweis: Wenn Sie anstelle von 255 1 eingeben, überwachen Sie den Standard in ... und 2 den Standardausgang (Sie müssen jedoch die Quelle ändern, um "tot" auf die projizierte Ausgabedateigröße festzulegen).
quelle