Frage

Wenn Scripting in bash oder einer anderen Schale in * NIX, während ein Befehl ausgeführt wird, der mehr als ein paar Sekunden dauert, wird ein Fortschrittsbalken erforderlich.

Zum Beispiel das Kopieren einer großen Datei, eine große TAR-Datei zu öffnen.

Welche Möglichkeiten empfehlen Sie Fortschrittsbalken hinzufügen Skripte zu schälen?

War es hilfreich?

Lösung

Sie können dies implementieren, indem eine Linie zu überschreiben. Verwenden Sie \r, um zurück zum Anfang der Zeile zu gehen, ohne \n an das Terminal zu schreiben.

Write \n wenn Sie fertig sind, die Linie zu fördern.

Mit echo -ne an:

  1. nicht drucken \n und
  2. erkennen Sequenzen wie \r zu entkommen.

Hier ist eine Demo:

echo -ne '#####                     (33%)\r'
sleep 1
echo -ne '#############             (66%)\r'
sleep 1
echo -ne '#######################   (100%)\r'
echo -ne '\n'

In einem Kommentar unten, puk erwähnt dies „versagt“, wenn Sie mit einer langen Linie beginnen und wollen dann eine kurze Zeile schreiben: In diesem Fall werden Sie müssen die Länge der langen Leitung zu überschreiben (zB mit Leerzeichen).

Andere Tipps

Sie auch wie ein Spinner zu tun:

Kann ich einen Spinner in Bash?

  

Sure!

i=1
sp="/-\|"
echo -n ' '
while true
do
    printf "\b${sp:i++%${#sp}:1}"
done
     

Jedes Mal, wenn die Schleife wiederholt, zeigt es das nächste Zeichen in den sp   Schnur, Umwickeln wie das Ende erreicht. (I ist die Position der   das aktuelle Zeichen anzuzeigen und $ {# sp} ist die Länge des sp   string).

     

Das \ b Zeichenfolge wird durch ein ‚Rückschritt‘ Zeichen ersetzt. Alternative,   Sie könnten mit \ r spielen zu Beginn der Linie zu gehen.

     

Wenn Sie es wollen, verlangsamen, legte einen Schlafbefehl innerhalb der Schleife   (Nach dem printf).

     

Ein POSIX-Äquivalent wäre:

sp='/-\|'
printf ' '
while true; do
    printf '\b%.1s' "$sp"
    sp=${sp#?}${sp%???}
done
     

Wenn Sie bereits eine Schleife haben, die viel Arbeit macht, können Sie den Anruf   folgende Funktion jeder Iteration am Anfang zu aktualisieren die   Spinner:

sp="/-\|"
sc=0
spin() {
   printf "\b${sp:sc++:1}"
   ((sc==${#sp})) && sc=0
}
endspin() {
   printf "\r%s\n" "$@"
}

until work_done; do
   spin
   some_work ...
done
endspin

Einige Beiträge haben gezeigt, wie man den Fortschritt des Befehls anzuzeigen. Um sie zu berechnen, müssen Sie, um zu sehen, wie viel Sie Fortschritte gemacht haben. Auf BSD-Systemen einige Befehle, wie dd (1), nehmen ein SIGINFO Signal, und ihre Fortschritte berichten. Auf Linux-Systemen reagiert einige Befehle ähnlich wie SIGUSR1. Wenn diese Möglichkeit vorhanden ist, können Sie Ihre Eingabe Rohr durch dd verarbeitet, um die Anzahl von Bytes zu überwachen.

Alternativ können Sie verwenden lsof die der Lesezeiger der Datei, Offset zu erhalten und dadurch berechnet den Fortschritt. Ich habe einen Befehl geschrieben, mit dem Namen pmonitor , dass der Fortschritt zeigt einen bestimmten Prozess oder eine Datei zu verarbeiten. Mit ihm können Sie Dinge tun, wie die folgenden.

$ pmonitor -c gzip
/home/dds/data/mysql-2015-04-01.sql.gz 58.06%

Eine frühere Version von Linux und FreeBSD-Shell-Skripten erscheint auf meinem Blog .

Mit dem Linux-Befehl pv:

http://linux.die.net/man/1/pv

es nicht die Größe nicht wissen, ob es in der Mitte des Stromes, aber es gibt eine Geschwindigkeit und Gesamt und von dort kann man herausfinden, wie lange soll es Feedback nehmen und erhalten, so dass Sie es wissen, nicht gehangen hat.

Haben Sie eine einfache Fortschrittsbalken-Funktion, die ich neulich schrieb:

#!/bin/bash
# 1. Create ProgressBar function
# 1.1 Input is currentState($1) and totalState($2)
function ProgressBar {
# Process data
    let _progress=(${1}*100/${2}*100)/100
    let _done=(${_progress}*4)/10
    let _left=40-$_done
# Build progressbar string lengths
    _fill=$(printf "%${_done}s")
    _empty=$(printf "%${_left}s")

# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:                           
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /\#}${_empty// /-}] ${_progress}%%"

}

# Variables
_start=1

# This accounts as the "totalState" variable for the ProgressBar function
_end=100

# Proof of concept
for number in $(seq ${_start} ${_end})
do
    sleep 0.1
    ProgressBar ${number} ${_end}
done
printf '\nFinished!\n'

oder verhaken es aus,
https://github.com/fearside/ProgressBar/

Ich war auf der Suche nach etwas mehr sexy als die gewählten Antwort, so hat mein eigenes Skript.

Vorschau

 progress-bar.sh in Aktion

Quelle

Ich habe es auf Github progress-bar.sh

progress-bar() {
  local duration=${1}


    already_done() { for ((done=0; done<$elapsed; done++)); do printf "▇"; done }
    remaining() { for ((remain=$elapsed; remain<$duration; remain++)); do printf " "; done }
    percentage() { printf "| %s%%" $(( (($elapsed)*100)/($duration)*100/100 )); }
    clean_line() { printf "\r"; }

  for (( elapsed=1; elapsed<=$duration; elapsed++ )); do
      already_done; remaining; percentage
      sleep 1
      clean_line
  done
  clean_line
}

Verwendung

 progress-bar 100

GNU tar hat eine nützliche Option, die gibt eine Funktionalität eines einfachen Fortschrittsbalken.

(...) Eine weitere verfügbare Kontrollpunkt Aktion ‚Punkt‘ (oder ‚‘). Er weist tar einen einzigen Punkt auf dem Standard-Angebot Strom zu drucken, z.

$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...

Der gleiche Effekt kann erhalten:

$ tar -c --checkpoint=.1000 /var

Eine einfachere Methode, die auf meinem System mit dem pipeview (pv) Dienstprogramm funktioniert.

srcdir=$1
outfile=$2


tar -Ocf - $srcdir | pv -i 1 -w 50 -berps `du -bs $srcdir | awk '{print $1}'` | 7za a -si $outfile

Ich möchte auch meine eigenen Fortschritt beitragen Bar

Es erreicht Teilzeichengenauigkeit von Halb Unicode-Blöcke

mit

 image description hier

-Code ist im Preis inbegriffen

Auf diese Weise können Sie visualisieren, dass ein Befehl noch ausgeführt wird:

while :;do echo -n .;sleep 1;done &
trap "kill $!" EXIT  #Die with parent if we die prematurely
tar zxf packages.tar.gz; # or any other command here
kill $! && trap " " EXIT #Kill the loop and unset the trap or else the pid might get reassigned and we might end up killing a completely different process

Das erzeugt eine unendliche while-Schleife , die im Hintergrund ausgeführt und Echos eines „“ jede Sekunde. Dies wird . in der Shell angezeigt werden soll. Führen Sie den tar Befehl oder über einen Befehl, den Sie möchten. Wenn dieser Befehl ausgeführt wird beendet dann töten der letzte Job im Hintergrund laufen -. Das ist die unendliche while-Schleife

Haben Sie nicht etwas Ähnliches gesehen so ... meine sehr einfache Lösung:

#!/bin/bash
BAR='####################'   # this is full bar, mine is 20 chars
for i in {1..20}; do
    echo -ne "\r${BAR:0:$i}" # print $i chars of $BAR from 0 position
    sleep .1
done
  • echo -n - drucken, ohne neue Zeile am Ende
  • echo -e - interpretieren Sonderzeichen beim Drucken
  • "\r" - Wagenrücklauf, ein besonderes Zeichen an den Anfang der Zeile zurück

habe ich es vor langer Zeit in einem einfachen „Hacking Video“ Code zur Simulation eingeben. ;)

Die meisten Unix-Befehle werden Sie nicht die Art von direktem Feedback geben, aus denen Sie dies tun können. Einige werden Sie die Ausgabe auf stdout geben oder stderr, dass Sie verwenden können.

Für so etwas wie Teer Sie die Option -v und Rohr des Ausgang mit einem Programm, das es liest für jede Zeile aktualisiert eine kleine Animation verwenden könnten. Als tar eine Liste von Dateien schreibt es ist das Programm entwirrt die Animation aktualisieren. Gehen Sie ein Prozent abgeschlossen würden Sie haben die Anzahl der Dateien kennen und die Zeilen zählen.

cp dieser Art der Ausgabe nicht so weit geben, wie ich weiß. Um den Fortschritt von cp überwachen würden Sie die Quell- und Zieldateien überwachen müssen und beobachten Sie die Größe des Ziels. Sie könnten ein kleines C-Programm schreiben die Verwendung von stat (2) Systemaufruf die bekommen Dateigröße. Dies würde die Größe der Quelle liest dann die Zieldatei abfragen und ein komplettes% Bar aktualisiert basierend auf der Größe der Datei Datum geschrieben.

Meine Lösung zeigt den Prozentsatz des Tarball, ist derzeit nicht komprimiert und geschrieben wird. ich benutze das beim Schreiben aus Dateisystem Bilder 2GB Wurzel. Du wirklich benötigen einen Fortschrittsbalken für diese Dinge. Was ich tue, ist die Verwendung gzip --list die Gesamt unkomprimierte Größe des bekommen Tarball. Daraus berechnet sich die Sperrfaktor benötigt die Datei in 100 Teile zu unterteilen. Schließlich drucke ich ein Prüfpunktnachricht für jeden Block. Für eine 2-GB-Datei dieses einen Block gibt etwa 10 MB. Wenn das zu groß ist, dann können Sie unterteilen den BLOCKING_FACTOR von 10 oder 100, aber es ist dann härter ziemlich Ausgabe in Form eines prozentualen zu drucken.

Angenommen, Sie verwenden Bash dann können Sie mit dem Folgende Shell-Funktion

untar_progress () 
{ 
  TARBALL=$1
  BLOCKING_FACTOR=$(gzip --list ${TARBALL} |
    perl -MPOSIX -ane '$.==2 && print ceil $F[1]/50688')
  tar --blocking-factor=${BLOCKING_FACTOR} --checkpoint=1 \
    --checkpoint-action='ttyout=Wrote %u%  \r' -zxf ${TARBALL}
}

Vor allem bar ist nicht die einzige Rohrfortschrittsanzeige. Die andere (vielleicht sogar mehr bekannt) ist pv (Rohr-Viewer).

Zweitens bar und pv können beispielsweise wie folgt verwendet werden:

$ bar file1 | wc -l 
$ pv file1 | wc -l

oder auch:

$ tail -n 100 file1 | bar | wc -l
$ tail -n 100 file1 | pv | wc -l

einen nützlichen Trick, wenn Sie den Einsatz von bar und pv in Befehlen machen wollen, die mit Dateien in Argumenten gegeben arbeiten, wie z.B. Kopie Datei1 Datei2, ist Prozess Substitution verwenden:

$ copy <(bar file1) file2
$ copy <(pv file1) file2

Prozess Substitution ist eine bash magische Sache, die temporäre Fifo Rohr Dateien / dev / fd / und verbinden stdout aus runned Prozess (in Klammern) durch dieses Rohr und kopieren Sie sieht es wie eine normale Datei (mit einer Ausnahme schafft, kann es lesen sie es nur vorwärts).

Update:

bar Befehl selbst ermöglicht auch das Kopieren. Nachdem man bar:

bar --in-file /dev/rmt/1cbn --out-file \
     tape-restore.tar --size 2.4g --buffer-size 64k

Aber Prozess Substitution ist meiner Meinung nach allgemeinerer Art und Weise, es zu tun. Ein nutzt cp Programm selbst.

Ich ziehe es verwenden Dialog mit dem - Messer Param. sehr oft in .deb Paketinstallationen und andere grundlegende Konfigurationskram vieler Distributionen verwendet. So müssen Sie das Rad nicht neu erfinden ... wieder

Nur einen int-Wert setzen 1-100 @stdin. Ein grundlegendes und dummes Beispiel:

for a in {1..100}; do sleep .1s; echo $a| dialog --gauge "waiting" 7 30; done

Ich habe diese / bin / Warten Sie Datei (mit chmod u + x perms) zum Kochen: P

#!/bin/bash
INIT=`/bin/date +%s`
NOW=$INIT
FUTURE=`/bin/date -d "$1" +%s`
[ $FUTURE -a $FUTURE -eq $FUTURE ] || exit
DIFF=`echo "$FUTURE - $INIT"|bc -l`

while [ $INIT -le $FUTURE -a $NOW -lt $FUTURE ]; do
    NOW=`/bin/date +%s`
    STEP=`echo "$NOW - $INIT"|bc -l`
    SLEFT=`echo "$FUTURE - $NOW"|bc -l`
    MLEFT=`echo "scale=2;$SLEFT/60"|bc -l`
    TEXT="$SLEFT seconds left ($MLEFT minutes)";
    TITLE="Waiting $1: $2"
    sleep 1s
    PTG=`echo "scale=0;$STEP * 100 / $DIFF"|bc -l`
    echo $PTG| dialog --title "$TITLE" --gauge "$TEXT" 7 72
done

if [ "$2" == "" ]; then msg="Espera terminada: $1";audio="Listo";
else msg=$2;audio=$2;fi 

/usr/bin/notify-send --icon=stock_appointment-reminder-excl "$msg"
espeak -v spanish "$audio"

So kann ich sagen:

Wait "34 min" "warm up the oven"

oder

Wait "dec 31" "happy new year"

Hier ist, wie es aussehen könnte

Hochladen einer Datei

[##################################################] 100% (137921 / 137921 bytes)

Warten auf einen Job zu beenden

[#########################                         ] 50% (15 / 30 seconds)

Einfache Funktion, die es

implementiert

Sie können nur copy-paste es zu Ihrem Script. Es ist nicht etwas anderes erfordert zu arbeiten.

PROGRESS_BAR_WIDTH=50  # progress bar length in characters

draw_progress_bar() {
  # Arguments: current value, max value, unit of measurement (optional)
  local __value=$1
  local __max=$2
  local __unit=${3:-""}  # if unit is not supplied, do not display it

  # Calculate percentage
  if (( $__max < 1 )); then __max=1; fi  # anti zero division protection
  local __percentage=$(( 100 - ($__max*100 - $__value*100) / $__max ))

  # Rescale the bar according to the progress bar width
  local __num_bar=$(( $__percentage * $PROGRESS_BAR_WIDTH / 100 ))

  # Draw progress bar
  printf "["
  for b in $(seq 1 $__num_bar); do printf "#"; done
  for s in $(seq 1 $(( $PROGRESS_BAR_WIDTH - $__num_bar ))); do printf " "; done
  printf "] $__percentage%% ($__value / $__max $__unit)\r"
}

Anwendungsbeispiel

Hier haben wir eine Datei hochladen und die Fortschrittsbalken bei jeder Iteration neu zu zeichnen. Es spielt keine Rolle, welcher Job tatsächlich so lange ausgeführt wird, wie wir zwei Werte erhalten können: Max. Wert und die aktuellen Wert

Im folgenden Beispiel wird der Maximalwert ist file_size und der aktuelle Wert wird durch eine bestimmte Funktion zugeführt und uploaded_bytes genannt.

# Uploading a file
file_size=137921

while true; do
  # Get current value of uploaded bytes
  uploaded_bytes=$(some_function_that_reports_progress)

  # Draw a progress bar
  draw_progress_bar $uploaded_bytes $file_size "bytes"

  # Check if we reached 100%
  if [ $uploaded_bytes == $file_size ]; then break; fi
  sleep 1  # Wait before redrawing
done
# Go to the newline at the end of upload
printf "\n"

APT Stil Fortschrittsbalken (Nicht für normale Ausgabe Pause)

EDIT: Für eine aktualisierte Version meiner Github Seite

war ich mit den Antworten auf diese Frage nicht zufrieden. Was ich persönlich auf der Suche nach einem ausgefallenen Fortschrittsbalken wurde wie von APT zu sehen ist.

hatte ich einen Blick auf dem C-Quellcode für APT und beschlossen, meine eigenen äquivalent für bash zu schreiben.

Dieser Fortschrittsbalken gut an der Unterseite des Terminals bleiben und wird mit jeder Ausgabe an das Endgerät gesendet nicht stören.

Bitte beachten Sie, dass die Bar ist derzeit auf 100 Zeichen festgelegt ist breit. Wenn Sie es auf die Größe des Terminals wollen skalieren, das ist ziemlich einfach, wie gut (die aktualisierte Version auf meiner GitHub Seite behandelt diese gut) zu erreichen.

Ich werde mein Skript hier posten. Anwendungsbeispiel:

source ./progress_bar.sh
echo "This is some output"
setup_scroll_area
sleep 1
echo "This is some output 2"
draw_progress_bar 10
sleep 1
echo "This is some output 3"
draw_progress_bar 50
sleep 1
echo "This is some output 4"
draw_progress_bar 90
sleep 1
echo "This is some output 5"
destroy_scroll_area

Das Skript (ich die Version auf meinem GitHub stattdessen wird dringend empfohlen):

#!/bin/bash

# This code was inspired by the open source C code of the APT progress bar
# http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/apt/trusty/view/head:/apt-pkg/install-progress.cc#L233

#
# Usage:
# Source this script
# setup_scroll_area
# draw_progress_bar 10
# draw_progress_bar 90
# destroy_scroll_area
#


CODE_SAVE_CURSOR="\033[s"
CODE_RESTORE_CURSOR="\033[u"
CODE_CURSOR_IN_SCROLL_AREA="\033[1A"
COLOR_FG="\e[30m"
COLOR_BG="\e[42m"
RESTORE_FG="\e[39m"
RESTORE_BG="\e[49m"

function setup_scroll_area() {
    lines=$(tput lines)
    let lines=$lines-1
    # Scroll down a bit to avoid visual glitch when the screen area shrinks by one row
    echo -en "\n"

    # Save cursor
    echo -en "$CODE_SAVE_CURSOR"
    # Set scroll region (this will place the cursor in the top left)
    echo -en "\033[0;${lines}r"

    # Restore cursor but ensure its inside the scrolling area
    echo -en "$CODE_RESTORE_CURSOR"
    echo -en "$CODE_CURSOR_IN_SCROLL_AREA"

    # Start empty progress bar
    draw_progress_bar 0
}

function destroy_scroll_area() {
    lines=$(tput lines)
    # Save cursor
    echo -en "$CODE_SAVE_CURSOR"
    # Set scroll region (this will place the cursor in the top left)
    echo -en "\033[0;${lines}r"

    # Restore cursor but ensure its inside the scrolling area
    echo -en "$CODE_RESTORE_CURSOR"
    echo -en "$CODE_CURSOR_IN_SCROLL_AREA"

    # We are done so clear the scroll bar
    clear_progress_bar

    # Scroll down a bit to avoid visual glitch when the screen area grows by one row
    echo -en "\n\n"
}

function draw_progress_bar() {
    percentage=$1
    lines=$(tput lines)
    let lines=$lines
    # Save cursor
    echo -en "$CODE_SAVE_CURSOR"

    # Move cursor position to last row
    echo -en "\033[${lines};0f"

    # Clear progress bar
    tput el

    # Draw progress bar
    print_bar_text $percentage

    # Restore cursor position
    echo -en "$CODE_RESTORE_CURSOR"
}

function clear_progress_bar() {
    lines=$(tput lines)
    let lines=$lines
    # Save cursor
    echo -en "$CODE_SAVE_CURSOR"

    # Move cursor position to last row
    echo -en "\033[${lines};0f"

    # clear progress bar
    tput el

    # Restore cursor position
    echo -en "$CODE_RESTORE_CURSOR"
}

function print_bar_text() {
    local percentage=$1

    # Prepare progress bar
    let remainder=100-$percentage
    progress_bar=$(echo -ne "["; echo -en "${COLOR_FG}${COLOR_BG}"; printf_new "#" $percentage; echo -en "${RESTORE_FG}${RESTORE_BG}"; printf_new "." $remainder; echo -ne "]");

    # Print progress bar
    if [ $1 -gt 99 ]
    then
        echo -ne "${progress_bar}"
    else
        echo -ne "${progress_bar}"
    fi
}

printf_new() {
    str=$1
    num=$2
    v=$(printf "%-${num}s" "$str")
    echo -ne "${v// /$str}"
}

für mich am einfachsten zu bedienen und am besten aussehenden so weit ist Befehl pv oder bar wie ein Typ bereits geschrieben

zum Beispiel: Notwendigkeit, eine Sicherung der gesamten Fahrt mit dd machen

Sie normalerweise verwenden dd if="$input_drive_path" of="$output_file_path"

mit pv können Sie es so machen:

dd if="$input_drive_path" | pv | dd of="$output_file_path"

und der Fortschritt geht direkt als dies STDOUT:

    7.46GB 0:33:40 [3.78MB/s] [  <=>                                            ]

, nachdem es gemacht Zusammenfassung aufkommt

    15654912+0 records in
    15654912+0 records out
    8015314944 bytes (8.0 GB) copied, 2020.49 s, 4.0 MB/s

Viele Antworten beschreiben Schreiben Sie Ihre eigenen Befehle für '\r' + $some_sort_of_progress_msg ausdrucken. Das Problem ist manchmal, dass Hunderte dieses Updates pro Sekunde heraus Druck wird den Prozess verlangsamen.

Wenn jedoch alle Ihrer Prozesse erzeugen Ausgang (zB 7z a -r newZipFile myFolder ausgibt jeder Dateinamen wie es komprimiert), dann eine einfache, schnell, schmerzlos und anpassbare Lösung vorhanden ist.

Installieren Sie das Python-Modul tqdm.

$ sudo pip install tqdm
$ # now have fun
$ 7z a -r -bd newZipFile myFolder | tqdm >> /dev/null
$ # if we know the expected total, we can have a bar!
$ 7z a -r -bd newZipFile myFolder | grep -o Compressing | tqdm --total $(find myFolder -type f | wc -l) >> /dev/null

Hilfe: tqdm -h. Ein Beispiel mehr Optionen:

$ find / -name '*.py' -exec cat \{} \; | tqdm --unit loc --unit_scale True | wc -l

Als Bonus erhalten Sie auch tqdm verwenden können Iterables in Python-Code zu wickeln.

https://github.com/tqdm/tqdm/blob/ Master / README.rst # Modul

Dies ist nur anwendbar gnome zenity verwenden. Zenity bietet eine große native Schnittstelle zu Bash-Skripte: https://help.gnome.org/users/zenity/stable/

Von Zenity Progress Bar Beispiel:

#!/bin/sh
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "20" ; sleep 1
echo "# Resetting cron jobs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "75" ; sleep 1
echo "# Rebooting system" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
  --title="Update System Logs" \
  --text="Scanning mail logs..." \
  --percentage=0

if [ "$?" = -1 ] ; then
        zenity --error \
          --text="Update canceled."
fi

Ich habe eine Antwort von von wiederholten Zeichen in Shell-Skript erstellen Zeichenfolge für char wiederholen. Ich habe zwei relativ kleine bash Versionen für Skripte, die Fortschrittsbalken angezeigt werden müssen (beispielsweise eine Schleife, die durch viele Dateien geht, aber nicht nützlich für große tar-Dateien oder Kopiervorgänge). Je schneller eine besteht aus zwei Funktionen, einerseits die Saiten für Balkenanzeige vorzubereiten:

preparebar() {
# $1 - bar length
# $2 - bar char
    barlen=$1
    barspaces=$(printf "%*s" "$1")
    barchars=$(printf "%*s" "$1" | tr ' ' "$2")
}

und man einen Fortschrittsbalken angezeigt werden:

progressbar() {
# $1 - number (-1 for clearing the bar)
# $2 - max number
    if [ $1 -eq -1 ]; then
        printf "\r  $barspaces\r"
    else
        barch=$(($1*barlen/$2))
        barsp=$((barlen-barch))
        printf "\r[%.${barch}s%.${barsp}s]\r" "$barchars" "$barspaces"
    fi
}

Es verwendet werden könnte, wie:

preparebar 50 "#"

, die für Balken bedeutet, mit 50 "#" Zeichen Strings vorbereiten, und danach:

progressbar 35 80

wird die Anzahl der „#“ Zeichen anzuzeigen, die 35/80 Verhältnis entspricht:

[#####################                             ]

Beachten Sie, dass Funktion zeigt die Bar auf der gleichen Linie immer wieder, bis Sie (oder ein anderes Programm) eine neue Zeile gedruckt wird. Wenn Sie setzen -1 als erster Parameter, würde die Bar gelöscht werden:

progressbar -1 80

Die langsamere Version ist alles in einer Funktion:

progressbar() {
# $1 - number
# $2 - max number
# $3 - number of '#' characters
    if [ $1 -eq -1 ]; then
        printf "\r  %*s\r" "$3"
    else
        i=$(($1*$3/$2))
        j=$(($3-i))
        printf "\r[%*s" "$i" | tr ' ' '#'
        printf "%*s]\r" "$j"
    fi
}

und es kann als (wie oben dasselbe Beispiel) verwendet werden:

progressbar 35 80 50

Wenn Sie progressbar auf stderr benötigen, fügen Sie einfach >&2 am Ende jedes printf Befehl.

Um Fortschritt der Aktivität zu zeigen, versuchen Sie die folgenden Befehle ein:

while true; do sleep 0.25 && echo -ne "\r\\" && sleep 0.25 && echo -ne "\r|" && sleep 0.25 && echo -ne "\r/" && sleep 0.25 && echo -ne "\r-"; done;

oder

while true; do sleep 0.25 && echo -ne "\rActivity: \\" && sleep 0.25 && echo -ne "\rActivity: |" && sleep 0.25 && echo -ne "\rActivity: /" && sleep 0.25 && echo -ne "\rActivity: -"; done;

oder

while true; do sleep 0.25 && echo -ne "\r" && sleep 0.25 && echo -ne "\r>" && sleep 0.25 && echo -ne "\r>>" && sleep 0.25 && echo -ne "\r>>>"; sleep 0.25 && echo -ne "\r>>>>"; done;

oder

while true; do sleep .25 && echo -ne "\r:Active:" && sleep .25 && echo -ne "\r:aCtive:" && sleep .25 && echo -ne "\r:acTive:" && sleep .25 && echo -ne "\r:actIve:" && sleep .25 && echo -ne "\r:actiVe:" && sleep .25 && echo -ne "\r:activE:"; done;

Man kann mit Flags / Variablen in der while-Schleife des Wertes / Ausmaß der Fortschritte zu überprüfen und anzuzeigen.

Basierend auf der Arbeit von Edouard Lopez, habe ich einen Fortschrittsbalken, der die Größe des Bildschirms passt, was auch immer es ist. Überprüfen Sie es heraus.

Es ist auch geschrieben auf Git Hub .

#!/bin/bash
#
# Progress bar by Adriano Pinaffo
# Available at https://github.com/adriano-pinaffo/progressbar.sh
# Inspired on work by Edouard Lopez (https://github.com/edouard-lopez/progress-bar.sh)
# Version 1.0
# Date April, 28th 2017

function error {
  echo "Usage: $0 [SECONDS]"
  case $1 in
    1) echo "Pass one argument only"
    exit 1
    ;;
    2) echo "Parameter must be a number"
    exit 2
    ;;
    *) echo "Unknown error"
    exit 999
  esac
}

[[ $# -ne 1 ]] && error 1
[[ $1 =~ ^[0-9]+$ ]] || error 2

duration=${1}
barsize=$((`tput cols` - 7))
unity=$(($barsize / $duration))
increment=$(($barsize%$duration))
skip=$(($duration/($duration-$increment)))
curr_bar=0
prev_bar=
for (( elapsed=1; elapsed<=$duration; elapsed++ ))
do
  # Elapsed
prev_bar=$curr_bar
  let curr_bar+=$unity
  [[ $increment -eq 0 ]] || {  
    [[ $skip -eq 1 ]] &&
      { [[ $(($elapsed%($duration/$increment))) -eq 0 ]] && let curr_bar++; } ||
    { [[ $(($elapsed%$skip)) -ne 0 ]] && let curr_bar++; }
  }
  [[ $elapsed -eq 1 && $increment -eq 1 && $skip -ne 1 ]] && let curr_bar++
  [[ $(($barsize-$curr_bar)) -eq 1 ]] && let curr_bar++
  [[ $curr_bar -lt $barsize ]] || curr_bar=$barsize
  for (( filled=0; filled<=$curr_bar; filled++ )); do
    printf "▇"
  done

  # Remaining
  for (( remain=$curr_bar; remain<$barsize; remain++ )); do
    printf " "
  done

  # Percentage
  printf "| %s%%" $(( ($elapsed*100)/$duration))

  # Return
  sleep 1
  printf "\r"
done
printf "\n"
exit 0

Genießen

Mit Vorschlägen oben aufgeführten habe ich beschlossen, meine eigenen Fortschrittsbalken zu implementieren.

#!/usr/bin/env bash

main() {
  for (( i = 0; i <= 100; i=$i + 1)); do
    progress_bar "$i"
    sleep 0.1;
  done
  progress_bar "done"
  exit 0
}

progress_bar() {
  if [ "$1" == "done" ]; then
    spinner="X"
    percent_done="100"
    progress_message="Done!"
    new_line="\n"
  else
    spinner='/-\|'
    percent_done="${1:-0}"
    progress_message="$percent_done %"
  fi

  percent_none="$(( 100 - $percent_done ))"
  [ "$percent_done" -gt 0 ] && local done_bar="$(printf '#%.0s' $(seq -s ' ' 1 $percent_done))"
  [ "$percent_none" -gt 0 ] && local none_bar="$(printf '~%.0s' $(seq -s ' ' 1 $percent_none))"

  # print the progress bar to the screen
  printf "\r Progress: [%s%s] %s %s${new_line}" \
    "$done_bar" \
    "$none_bar" \
    "${spinner:x++%${#spinner}:1}" \
    "$progress_message"
}

main "$@"

habe ich eine reine Shell-Version für ein eingebettetes System nutzt:

  • / usr / bin / dd des SIGUSR1 Signalverarbeitung Funktion.

    Grundsätzlich, wenn Sie einen 'töten SIGUSR1 $ (pid_of_running_dd_process)' senden, es wird ausgegeben eine Zusammenfassung der Durchsatzgeschwindigkeit und Menge übertragen.

  • Backgrounding dd und dann regelmäßig nach Aktualisierungen abfragt und zum Erzeugen Hash-Zecken wie Old-School-FTP-Clients verwendet.

  • Die Verwendung von / dev / stdout als Ziel für Nicht-stdout freundliche Programme wie scp

Das Endergebnis können Sie einen beliebigen Dateiübertragung zu übernehmen und den aktuellen Stand bekommen, die wie Old-School-FTP ‚Hash‘ Ausgabe sieht, wo man nur einen Hash-Markierung für jeden X Bytes bekommen würde.

Dies ist kaum Produktionsqualität Code, aber Sie bekommen die Idee. Ich denke, es ist süß.

Für das, was es wert ist, die tatsächliche Byte-Zählung möglicherweise nicht korrekt in der Anzahl der Hash-Werte widerspiegeln - Sie haben eine mehr oder weniger abhängig von Rundungsfragen. Tun Sie dies nicht als Teil eines Testskript verwenden, ist es nur Augenschmaus. Und, ja, ich bin mir bewusst, diese schrecklich ineffizient ist - es ist ein Shell-Skript ist, und ich entschuldige mich nicht dafür für sie.

Beispiele mit wget, scp und tftp am Ende zur Verfügung gestellt. Es sollte mit etwas arbeiten, das aussendet Daten hat. Achten Sie darauf, / dev / stdout für Programme, die nicht stdout freundlich sind.

#!/bin/sh
#
# Copyright (C) Nathan Ramella (nar+progress-script@remix.net) 2010 
# LGPLv2 license
# If you use this, send me an email to say thanks and let me know what your product
# is so I can tell all my friends I'm a big man on the internet!

progress_filter() {

        local START=$(date +"%s")
        local SIZE=1
        local DURATION=1
        local BLKSZ=51200
        local TMPFILE=/tmp/tmpfile
        local PROGRESS=/tmp/tftp.progress
        local BYTES_LAST_CYCLE=0
        local BYTES_THIS_CYCLE=0

        rm -f ${PROGRESS}

        dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
                | grep --line-buffered -E '[[:digit:]]* bytes' \
                | awk '{ print $1 }' >> ${PROGRESS} &

        # Loop while the 'dd' exists. It would be 'more better' if we
        # actually looked for the specific child ID of the running 
        # process by identifying which child process it was. If someone
        # else is running dd, it will mess things up.

        # My PID handling is dumb, it assumes you only have one running dd on
        # the system, this should be fixed to just get the PID of the child
        # process from the shell.

        while [ $(pidof dd) -gt 1 ]; do

                # PROTIP: You can sleep partial seconds (at least on linux)
                sleep .5    

                # Force dd to update us on it's progress (which gets
                # redirected to $PROGRESS file.
                # 
                # dumb pid handling again
                pkill -USR1 dd

                local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS)
                local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ))

                # Don't print anything unless we've got 1 block or more.
                # This allows for stdin/stderr interactions to occur
                # without printing a hash erroneously.

                # Also makes it possible for you to background 'scp',
                # but still use the /dev/stdout trick _even_ if scp
                # (inevitably) asks for a password. 
                #
                # Fancy!

                if [ $XFER_BLKS -gt 0 ]; then
                        printf "#%0.s" $(seq 0 $XFER_BLKS)
                        BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE
                fi
        done

        local SIZE=$(stat -c"%s" $TMPFILE)
        local NOW=$(date +"%s")

        if [ $NOW -eq 0 ]; then
                NOW=1
        fi

        local DURATION=$(($NOW-$START))
        local BYTES_PER_SECOND=$(( SIZE / DURATION ))
        local KBPS=$((SIZE/DURATION/1024))
        local MD5=$(md5sum $TMPFILE | awk '{ print $1 }')

        # This function prints out ugly stuff suitable for eval() 
        # rather than a pretty string. This makes it a bit more 
        # flexible if you have a custom format (or dare I say, locale?)

        printf "\nDURATION=%d\nBYTES=%d\nKBPS=%f\nMD5=%s\n" \
            $DURATION \
            $SIZE \
            $KBPS \
            $MD5
}

Beispiele:

echo "wget"
wget -q -O /dev/stdout http://www.blah.com/somefile.zip | progress_filter

echo "tftp"
tftp -l /dev/stdout -g -r something/firmware.bin 192.168.1.1 | progress_filter

echo "scp"
scp user@192.168.1.1:~/myfile.tar /dev/stdout | progress_filter

Falls Sie haben einen zeitlichen Fortschrittsbalken zeigen (von im Voraus zu wissen, die Zeit zeigt), können Sie Python verwenden wie folgt:

#!/bin/python
from time import sleep
import sys

if len(sys.argv) != 3:
    print "Usage:", sys.argv[0], "<total_time>", "<progressbar_size>"
    exit()

TOTTIME=float(sys.argv[1])
BARSIZE=float(sys.argv[2])

PERCRATE=100.0/TOTTIME
BARRATE=BARSIZE/TOTTIME

for i in range(int(TOTTIME)+1):
    sys.stdout.write('\r')
    s = "[%-"+str(int(BARSIZE))+"s] %d%% "
    sys.stdout.write(s % ('='*int(BARRATE*i), int(PERCRATE*i)))
    sys.stdout.flush()
    SLEEPTIME = 1.0
    if i == int(TOTTIME): SLEEPTIME = 0.1
    sleep(SLEEPTIME)
print ""

Dann vorausgesetzt, Sie den Python-Skript als progressbar.py gespeichert, dann ist es möglich, die Fortschrittsbalken aus dem Bash-Skript, um zu zeigen, indem Sie den folgenden Befehl ausführen:

python progressbar.py 10 50

Es wäre ein Fortschrittsbalken Größe 50 Zeichen zeigen und „running“ für 10 Sekunden.

Ich habe auf der Antwort gebaut von fearside versehen

Diese Verbindung zu einer Oracle-Datenbank der Fortschritt eines RMAN wiederherstellen abgerufen werden.

#!/bin/bash

 # 1. Create ProgressBar function
 # 1.1 Input is currentState($1) and totalState($2)
 function ProgressBar {
 # Process data
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
# Build progressbar string lengths
_fill=$(printf "%${_done}s")
_empty=$(printf "%${_left}s")

# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%"

}

function rman_check {
sqlplus -s / as sysdba <<EOF
set heading off
set feedback off
select
round((sofar/totalwork) * 100,0) pct_done
from
v\$session_longops
where
totalwork > sofar
AND
opname NOT LIKE '%aggregate%'
AND
opname like 'RMAN%';
exit
EOF
}

# Variables
_start=1

# This accounts as the "totalState" variable for the ProgressBar function
_end=100

_rman_progress=$(rman_check)
#echo ${_rman_progress}

# Proof of concept
#for number in $(seq ${_start} ${_end})

while [ ${_rman_progress} -lt 100 ]
do

for number in _rman_progress
do
sleep 10
ProgressBar ${number} ${_end}
done

_rman_progress=$(rman_check)

done
printf '\nFinished!\n'
#!/bin/bash

function progress_bar() {
    bar=""
    total=10
    [[ -z $1 ]] && input=0 || input=${1}
    x="##"
   for i in `seq 1 10`; do
        if [ $i -le $input ] ;then
            bar=$bar$x
        else
            bar="$bar  "
       fi
    done
    #pct=$((200*$input/$total % 2 + 100*$input/$total))
    pct=$(($input*10))
    echo -ne "Progress : [ ${bar} ] (${pct}%) \r"    
    sleep 1
    if [ $input -eq 10 ] ;then
        echo -ne '\n'
    fi

}

könnte eine Funktion erstellen, die diese auf einer Skala zieht sagen 1-10 für die Anzahl der Bars:

progress_bar 1
echo "doing something ..."
progress_bar 2
echo "doing something ..."
progress_bar 3
echo "doing something ..."
progress_bar 8
echo "doing something ..."
progress_bar 10

https://github.com/extensionsapp/progre.sh

Erstellen 40 Prozent Fortschritt: progreSh 40

#!/bin/bash
tot=$(wc -c /proc/$$/fd/255 | awk '/ /{print $1}')
now() {
echo $(( 100* ($(awk '/^pos:/{print $2}' < /proc/$$/fdinfo/255)-166) / (tot-166) )) "%"
}
now;
now;
now;
now;
now;
now;
now;
now;
now;

Ausgabe:

0 %
12 %
25 %
37 %
50 %
62 %
75 %
87 %
100 %

Hinweis: Wenn anstelle von 255 Sie 1 gesetzt werden Sie den Standard in ... mit 2 den Standard Monitorausgang (aber Sie müssen die Quelle ändern, um „tot“ zu der projizierten Größe der Ausgabedatei)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top