Crea una barra de progreso en bash

13

¿Cómo puedo crear una barra de progreso con bash?

Este es mi guión:

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

Quiero reemplazar echo 'loading 50%'con cualquier cosa para crear una barra de progreso.

Black Hawk
fuente
1
¿Una barra de progreso en la terminal o una barra de progreso en una ventana GUI separada?
Byte Commander
2
En la terminal
Black Hawk
El etapodría hacer lo que quieras.
aioobe

Respuestas:

14

whiptail viene preinstalado en Ubuntu y muchas otras distribuciones, y mostrará elementos de progreso en pantalla completa (pero aún basados ​​en terminales).

dialoges un superconjunto de whiptail, por lo que este ejemplo funcionará igualmente bien con ambos. Proporciona elementos de interfaz de usuario más avanzados, por lo que puede ser útil si está buscando interacción del usuario, como selectores de archivos y formularios, pero tiene la desventaja de no venir preinstalado en muchos sistemas.

Whiptail

diálogo

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

Tenga en cuenta que la salida del script se interpreta como un porcentaje, por lo que puede que tenga que ajustar su salida en consecuencia.

Whiptail y Dialog también le permiten modificar el texto en tiempo de ejecución a través de una sintaxis bastante críptica:

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

pvmuestra el progreso de un archivo o secuencia que se canaliza a través de él. Sin embargo, no puede usarse (¿fácilmente?) Para mostrar el progreso de una operación personalizada, como un bucle. Está diseñado específicamente para transmisiones.

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

Algunos ejemplos del mundo real son pvútiles:

# 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

No conozco ningún comando que proporcione barras de progreso de una línea en el estilo de pvo wget, pero hay muchos scripts simples de Bash / Perl / sed que agregarán esa funcionalidad, como otros han compartido aquí.

Mikkel
fuente
Para mostrar el proceso de un bucle con pvusted, puede hacer que busque la salida del bucle o crear alguna salida falsa, por ejemplo, un echoen cada iteración, canalizarlo pvy darle el recuento de iteración -s. Si no se desea, recuerde redirigir el stdout del bucle a /dev/null. Aquí hay un ejemplo que muestra este enfoque .
postre
6

Puede usar zenitypara crear ventanas de diálogo GTK simples. Una de las opciones disponibles es un diálogo de barra de progreso.

Usted crea dicha ventana usando zenity --progress. Para que sea útil, debe especificar más información agregando algunas de las opciones a continuación (extracto 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

Hay dos modos:

  • pulsante : la barra de progreso está pulsando, solo indica que algo se está ejecutando, pero no dice nada sobre el progreso. Para ello, configura la --pulsatingopción.

  • manual : debe canalizar el porcentaje de progreso actual a la zenityentrada estándar del comando para actualizar la barra de progreso.
    Un ejemplo de esto podría verse así a continuación. Tenga en cuenta que los comandos anteriores se agrupan en una subshell para que toda la salida se redirija al zenitycuadro de diálogo y no solo la del último comando:

    (echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress
Byte Commander
fuente
Por si acaso esto también sería una opción.
Byte Commander
1
Lo siento querida, esta es la ventana de la barra de progreso de la GUI, quiero crear una barra de progreso en la terminal, por ejemplo, quiero verla mientras el script está comprobando ==>[ ###########--------------] 52%
Black Hawk
1
Si entiendo. Es solo que ya había escrito la mitad de mi respuesta cuando dijiste eso, así que decidí publicarlo de todos modos en caso de que alguien más lo necesite en el futuro. Espero que no te importe, ya que también hay bastantes soluciones basadas en terminales.
Byte Commander
5

Este código lo hará, y no requiere nada (aparte de bash, por supuesto). Imprime #letreros, como usted preguntó en su comentario:

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

Sin embargo, si tiene mucho que verificar, esto solo llenará su pantalla con #signos. Para solucionar ese problema, intente este código:

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

Cambie el 5 en la primera línea ( lenProgressBar=5) a la longitud que desea que tenga su barra de progreso. Tardará más en imprimir un #letrero con barras de progreso de menor longitud que con barras de mayor longitud, pero no permita que la longitud de la barra de progreso exceda el tamaño de su pantalla; no funcionará bien si lo haces. (No le permitirá usar una barra de progreso superior a la cantidad de elementos que está revisando o inferior a 1)

insert_name_here
fuente
1
Puede usar tput colspara detectar el ancho de la ventana de terminal y escalar la barra de progreso en consecuencia.
Mikkel
1

Aquí hay otro enfoque que usa códigos de 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 "\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
fuente