Créer une barre de progression dans bash

13

Comment puis-je créer une barre de progression avec bash?

Voici mon script:

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

Je veux remplacer echo 'loading 50%'par n'importe quoi pour créer une barre de progression.

Black Hawk
la source
1
Une barre de progression dans le terminal ou une barre de progression dans une fenêtre GUI distincte?
Byte Commander
2
Dans le terminal
Black Hawk
Ils etapourraient faire ce que vous voulez.
aioobe

Réponses:

14

whiptail est préinstallé sur Ubuntu et de nombreuses autres distributions, et affichera des éléments de progression en plein écran (mais toujours basés sur les terminaux).

dialogest un surensemble de whiptail, donc cet exemple fonctionnera aussi bien avec les deux. Il fournit des éléments d'interface utilisateur plus avancés, il peut donc être utile si vous recherchez une interaction utilisateur telle que des sélecteurs de fichiers et des formulaires, mais il a l'inconvénient de ne pas être préinstallé sur de nombreux systèmes.

whiptail

dialogue

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

Notez que la sortie du script est interprétée comme un pourcentage, vous devrez donc peut-être ajuster votre sortie en conséquence.

Whiptail et Dialog vous permettent également de modifier le texte au moment de l'exécution via une syntaxe plutôt cryptique:

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

pvaffiche la progression d'un fichier ou d'un flux en cours d'acheminement. Il ne peut cependant pas (facilement?) Être utilisé pour montrer la progression d'une opération personnalisée telle qu'une boucle. Il est spécialement conçu pour les flux.

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

Quelques exemples concrets où cela pvest utile:

# 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

Je ne connais aucune commande qui donne des barres de progression d'une ligne dans le style de pvou wget, mais il existe de nombreux scripts Bash / Perl / sed simples qui ajouteront cette fonctionnalité, comme d'autres l'ont partagé ici.

Mikkel
la source
Pour afficher le processus d'une boucle avec pvvous pouvez soit lui faire rechercher la sortie de la boucle ou créer une fausse sortie, par exemple un echodans chaque itération, le diriger vers pvet lui donner le nombre d'itérations avec -s. Si ce n'est pas souhaité, n'oubliez pas de rediriger la sortie standard de la boucle vers /dev/null. Voici un exemple montrant cette approche .
dessert le
6

Vous pouvez utiliser zenitypour créer des fenêtres de dialogue GTK simples. L'une des options disponibles est une boîte de dialogue de barre de progression.

Vous créez une telle fenêtre en utilisant zenity --progress. Pour le rendre utile, vous devez spécifier plus d'informations en ajoutant certaines des options ci-dessous (extrait de 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

Il existe deux modes:

  • pulsation : la barre de progression clignote, elle indique simplement que quelque chose fonctionne, mais ne dit rien sur la progression. Pour ce faire, définissez l' --pulsatingoption.

  • manuel : vous devez diriger le pourcentage de progression actuel vers l' zenityentrée standard de la commande pour mettre à jour la barre de progression.
    Un exemple pourrait ressembler à cela ci-dessous. Notez que les commandes précédentes sont regroupées dans un sous-shell afin que toute la sortie soit redirigée vers la zenityboîte de dialogue et pas seulement celle de la dernière commande:

    (echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress
Byte Commander
la source
Au cas où ce serait également une option.
Byte Commander
1
Désolé mon cher, ce sont les fenêtres de la barre de progression de l'interface graphique, je veux créer une barre de progression dans le terminal, par exemple, je veux la voir pendant que le script vérifie ==>[ ###########--------------] 52%
Black Hawk
1
Oui je comprends. C'est juste que j'avais déjà écrit la moitié de ma réponse lorsque vous avez dit cela, j'ai donc décidé de le publier de toute façon au cas où quelqu'un d'autre en aurait besoin à l'avenir. J'espère que cela ne vous dérange pas, car il existe également quelques solutions basées sur les terminaux.
Byte Commander
5

Ce code le fera et ne nécessite rien (autre que bash, bien sûr). Il imprime des #signes, comme vous l'avez demandé dans votre commentaire:

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

Cependant, si vous avez beaucoup à vérifier, cela ne fera que remplir votre écran de #signes. Pour résoudre ce problème, essayez ce code:

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

Remplacez le 5 de la première ligne ( lenProgressBar=5) par la longueur souhaitée pour votre barre de progression. L'impression d'un #panneau avec des barres de progression de longueur inférieure prendra plus de temps qu'avec des barres de longueur supérieure, mais ne laissez pas la longueur de la barre de progression dépasser la taille de votre écran; cela ne fonctionnera pas bien si vous le faites. (Il ne vous permettra pas d'utiliser une barre de progression supérieure au nombre d'éléments que vous vérifiez ou inférieure à 1)

insert_name_here
la source
1
Vous pouvez utiliser tput colspour détecter la largeur de la fenêtre du terminal et mettre à l'échelle la barre de progression en conséquence.
Mikkel
1

Voici une autre approche utilisant les codes d'échappement ansi:

#!/bin/bash

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

echo
echo -n "Working... "
echo -ne "\033[1;32m\033[7m\033[?25l"

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

echo -ne "\r\033[0m\033[K\033[?25h"
echo $result
echo
bashBedlam
la source