Erstelle einen Fortschrittsbalken in bash

13

Wie kann ich einen Fortschrittsbalken mit bash erstellen?

Das ist mein Skript:

 #!/bin/bash
 pass='number1 number12 number13 number14 number15 number16'
 chk='number14'
 for i in $pass ; do
 if [ "$i" == "$chk" ]; then
 echo ' Found ^_^'
 else
 echo 'loading 50%'
 fi
 done

Ich möchte echo 'loading 50%' durch irgendetwas ersetzen, um einen Fortschrittsbalken zu erstellen.

    
Black Hawk 17.03.2016, 16:34
quelle

4 Antworten

14

whiptail ist auf Ubuntu und vielen anderen Distributionen vorinstalliert und zeigt Vollbild (aber immer noch basierte) Fortschrittselemente.

dialog ist eine Obermenge von whiptail , daher wird dieses Beispiel bei beiden gleichermaßen funktionieren. Es bietet erweiterte UI-Elemente, so dass es nützlich sein kann, wenn Sie Benutzerinteraktion wie Dateiauswahl und Formulare suchen, aber es hat den Nachteil, nicht auf vielen Systemen vorinstalliert.

for i in $(seq 1 100)
do
    sleep 0.1 
    echo $i
done | whiptail --title 'Test script' --gauge 'Running...' 6 60 0

Beachten Sie, dass die Skriptausgabe als Prozentsatz interpretiert wird. Daher müssen Sie möglicherweise die Ausgabe entsprechend anpassen.

Whiptail und Dialog ermöglichen Ihnen auch, den Text zur Laufzeit über eine ziemlich kryptische Syntax zu ändern:

phases=( 
    'Locating Jebediah Kerman...'
    'Motivating Kerbals...'
    'Treating Kessler Syndrome...'
    'Recruiting Kerbals...'
)   

for i in $(seq 1 100); do  
    sleep 0.1

    if [ $i -eq 100 ]; then
        echo -e "XXX\n100\nDone!\nXXX"
    elif [ $(($i % 25)) -eq 0 ]; then
        let "phase = $i / 25"
        echo -e "XXX\n$i\n${phases[phase]}\nXXX"
    else
        echo $i
    fi 
done | whiptail --title 'Kerbal Space Program' --gauge "${phases[0]}" 6 60 0

pv zeigt den Fortschritt einer Datei oder eines Streams an. Es kann jedoch nicht (einfach?) Verwendet werden, um den Fortschritt einer benutzerdefinierten Operation wie einer Schleife anzuzeigen. Es ist speziell für Streams konzipiert.

$ head -c 1G < /dev/urandom | pv -s 1G > /dev/null
 277MB 0:00:16 [17.4MB/s] [========>                           ] 27% ETA 0:00:43

Einige Beispiele aus der Praxis, bei denen pv nützlich ist:

# progress while importing a DB dump
pv mybigfile.sql | mysql -uroot -p dbname

# importing straight from a remote server
ssh user@server 'cat mybigfile.sql.gz' | pv | gzip -cd | mysql -uroot -p dbname

# taking a snapshot of a btrfs partition
btrfs send /snapshots/$date | pv | btrfs receive /mnt/backup/root

Ich kenne keine Befehle, die einzeilige Fortschrittsbalken im Stil von pv oder wget enthalten, aber es gibt viele einfache Bash / Perl / sed-Skripte, die diese Funktionalität hinzufügen, wie andere auch habe hier geteilt.

    
Mikkel 17.03.2016 18:14
quelle
6

Sie können zenity verwenden, um einfache GTK-Dialogfenster zu erstellen. Eine der verfügbaren Optionen ist ein Fortschrittsbalken-Dialog.

Sie erstellen ein solches Fenster mit zenity --progress . Um es nützlich zu machen, sollten Sie weitere Informationen angeben, indem Sie einige der folgenden Optionen hinzufügen (Auszug aus man zenity ):

   Progress options
   --text=STRING
          Set the dialog text
   --percentage=INT
          Set initial percentage
   --auto-close
          Close dialog when 100% has been reached
   --auto-kill
          Kill parent process if cancel button is pressed
   --pulsate
          Pulsate progress bar
   --no-cancel
          Hides the cancel button

Es gibt zwei Modi:

  • pulsierend : Der Fortschrittsbalken pulsiert, zeigt nur an, dass etwas läuft, sagt aber nichts über den Fortschritt aus. Sie tun dies, indem Sie die Option --pulsating setzen.

  • manuell : Sie müssen den aktuellen Fortschrittsprozentsatz an die Standardeingabe des Befehls zenity übergeben, um den Fortschrittsbalken zu aktualisieren.
    Ein Beispiel dafür könnte unten aussehen. Beachten Sie, dass die vorherigen Befehle zu einer Untershell gruppiert sind, so dass die gesamte Ausgabe zum Dialogfeld zenity und nicht nur zum letzten Befehl umgeleitet wird:

    (echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress
    
Byte Commander 17.03.2016 16:58
quelle
4

Dieser Code wird es tun und benötigt nichts (außer bash, natürlich). Er gibt # signs aus, wie Sie in Ihrem Kommentar gefragt haben:

pass='number1 number12 number13 number14 number15 number16'
chk='number14'
passarr=($pass)
lenProgressBar=${#passarr[@]}

echo -n '['
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -n '-'
    ((i++))
done

echo -n ']'
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -e -n '\b'
    ((i++))
done

echo -e -n '\b'
for i in $pass ; do
    if [ "$i" = "$chk" ]; then
        echo -e '#\nFound ^_^'
        break
    else
        echo -n '#'
    fi
done

Wenn Sie jedoch viel zu prüfen haben, füllt dies Ihren Bildschirm mit # signs. Versuchen Sie diesen Code, um dieses Problem zu beheben:

lenProgressBar=5
pass='number1 number12 number13 number14 number15 number16'
chk='number14'
passarr=($pass)
lenPass=${#passarr[@]}

if [ $lenProgressBar -gt $lenPass ]; then
    lenProgressBar=lenPass
elif [ $lenProgressBar -lt 1 ]; then
    lenProgressBar=1
fi

let "chksForEqualsPrint = $lenPass / $lenProgressBar"
echo -n '['
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -n '-'
    ((i++))
done

echo -n ']'
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -e -n '\b'
    ((i++))
done

echo -e -n '\b'
n=1

for i in $pass ; do
    if [ "$i" = "$chk" ]; then
        echo -e '\nFound ^_^'
        break
    else
        if [ $n -eq $chksForEqualsPrint ]; then
            echo -n '#'
            n=1
        else
            ((n++))
        fi
    fi
done

Ändere die 5 in der ersten Zeile ( lenProgressBar=5 ) auf die Länge, die dein Fortschrittsbalken haben soll. Es dauert länger, ein # -Zeichen mit Fortschrittsbalken niedrigerer Länge zu drucken als mit denen mit höherer Länge, aber die Länge des Fortschrittsbalkens darf die Bildschirmgröße nicht überschreiten. Es wird nicht gut funktionieren, wenn Sie es tun. (Es wird nicht möglich sein, einen Fortschrittsbalken höher als die Anzahl der Elemente zu verwenden, die Sie überprüfen oder niedriger als 1)

    
insert_name_here 17.03.2016 19:09
quelle
0

Hier ist ein weiterer Ansatz, der ansi-Escape-Codes verwendet:

#!/bin/bash

pass='number1 number2 number 3 number4 number12 number13 number14 number15 number16'
chk='number15'
result="Not Found!"

echo
echo -n "Working... "
echo -ne "3[1;32m3[7m3[?25l"

for i in $pass ; do
   sleep .4s
   if [ "$i" == "$chk" ]; then
      result="  Found ^_^"
      break
   else
      echo -n " "
   fi
done

echo -ne "\r3[0m3[K3[?25h"
echo $result
echo
    
bashBedlam 21.07.2016 04:19
quelle

Tags und Links