¿Cómo agregar una barra de progreso a un script de shell?

Resuelto Tom Feiner asked hace 15 años • 42 respuestas

Al escribir scripts en bash o cualquier otro shell en *NIX, mientras se ejecuta un comando que tardará más de unos pocos segundos, se necesita una barra de progreso.

Por ejemplo, copiar un archivo grande, abrir un archivo tar grande.

¿Qué formas recomienda para agregar barras de progreso a los scripts de shell?

Tom Feiner avatar Oct 26 '08 21:10 Tom Feiner
Aceptado

Puede implementar esto sobrescribiendo una línea. Úselo \rpara volver al principio de la línea sin escribir \nen la terminal.

Escribe \ncuando hayas terminado para avanzar en la línea.

Úselo echo -nepara:

  1. no imprimir \ny
  2. para reconocer secuencias de escape como \r.

Aquí hay una demostración:

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

En un comentario a continuación, puk menciona que esto "falla" si comienza con una línea larga y luego desea escribir una línea corta: En este caso, necesitará sobrescribir la longitud de la línea larga (por ejemplo, con espacios).

Mitch Haile avatar Oct 26 '2008 14:10 Mitch Haile

Quizás también te interese cómo hacer una ruleta :

¿Puedo hacer una ruleta en Bash?

¡Seguro!

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

Cada vez que el bucle se repite, muestra el siguiente carácter en la cadena sp, y continúa hasta llegar al final. (i es la posición del carácter actual que se mostrará y ${#sp} es la longitud de la cadena sp).

La cadena \b se reemplaza por un carácter de "retroceso". Alternativamente, puedes jugar con \r para volver al principio de la línea.

Si desea que se ralentice, coloque un comando de suspensión dentro del bucle (después de printf).

Un equivalente POSIX sería:

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

Si ya tiene un bucle que hace mucho trabajo, puede llamar a la siguiente función al comienzo de cada iteración para actualizar el control giratorio:

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
Daenyth avatar Jul 25 '2010 20:07 Daenyth