Crea una barra di avanzamento in bash

13

Come posso creare una barra di avanzamento con bash?

Questo è il mio 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

Voglio sostituire echo 'loading 50%' con qualsiasi cosa per creare una barra di avanzamento.

    
posta Black Hawk 17.03.2016 - 16:34
fonte

4 risposte

14

whiptail viene preinstallato su Ubuntu e molte altre distribuzioni e mostrerà a schermo intero (ma ancora terminale) basato) elementi di progresso.

dialog è un superset di whiptail , quindi questo esempio funzionerà altrettanto bene con entrambi. Fornisce elementi di interfaccia utente più avanzati, quindi potrebbe rivelarsi utile se stai cercando interazioni con l'utente, come i selettori di file e i moduli, ma ha lo svantaggio di non venire preinstallato su molti sistemi.

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

Si noti che l'output dello script è interpretato come una percentuale, quindi potrebbe essere necessario regolare l'output di conseguenza.

Whiptail e Dialog ti permettono anche di modificare il testo in fase di esecuzione tramite una sintassi piuttosto criptica:

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 mostra l'avanzamento di un file o di un flusso che viene canalizzato attraverso di esso. Tuttavia, non può essere (facilmente?) Utilizzato per mostrare l'avanzamento di un'operazione personalizzata come un ciclo. È progettato specificamente per i flussi.

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

Alcuni esempi reali in cui pv è 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

Non conosco alcun comando che dia barre di avanzamento di una riga nello stile di pv o wget , ma ci sono molti semplici script Bash / Perl / sed che aggiungeranno quella funzionalità, come altri ho condiviso qui.

    
risposta data Mikkel 17.03.2016 - 18:14
fonte
6

Puoi usare zenity per creare finestre di dialogo GTK semplici. Una delle opzioni disponibili è una finestra di dialogo della barra di avanzamento.

Crea una finestra simile usando zenity --progress . Per renderlo utile, devi specificare maggiori informazioni aggiungendo alcune delle opzioni seguenti (estratto da 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

Ci sono due modalità:

  • pulsante : la barra di avanzamento pulsa, indica solo che qualcosa è in esecuzione, ma non dice nulla sullo stato di avanzamento. Puoi farlo impostando l'opzione --pulsating .

  • manuale : devi ridimensionare la percentuale di avanzamento corrente con l'input standard del comando zenity per aggiornare la barra di avanzamento.
    Un esempio per questo potrebbe apparire come sotto. Nota che i comandi precedenti sono raggruppati in una subshell in modo che tutto l'output sia reindirizzato alla finestra di dialogo zenity e non solo a quello dell'ultimo comando:

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

Questo codice lo farà, e non richiede nulla (tranne bash, ovviamente). Stampa # segni, come hai chiesto nel tuo commento:

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

Tuttavia, se hai molto da controllare, questo riempirà lo schermo solo con # segni. Per risolvere il problema, prova questo codice:

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

Cambia il 5 nella prima riga ( lenProgressBar=5 ) alla lunghezza che vuoi che la barra di avanzamento sia. Ci vorrà più tempo per stampare un segno # con barre di avanzamento di lunghezza inferiore rispetto a quelle di lunghezza maggiore, ma non lasciare che la lunghezza della barra di avanzamento superi le dimensioni dello schermo; non funzionerà bene se lo fai. (Non ti consentirà di utilizzare una barra di avanzamento superiore al numero di elementi che stai controllando o inferiore a 1)

    
risposta data insert_name_here 17.03.2016 - 19:09
fonte
0

Ecco un altro approccio che utilizza i codici di escape 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 "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
    
risposta data bashBedlam 21.07.2016 - 04:19
fonte

Leggi altre domande sui tag