Al crear scripts en bash o cualquier otro shell en * NIX, mientras se ejecuta un comando que tomará más de unos segundos, se necesita una barra de progreso.
Por ejemplo, copiar un archivo grande, abrir un archivo tar grande.
¿De qué maneras recomienda agregar barras de progreso a los scripts de shell?
Respuestas:
Puede implementar esto sobrescribiendo una línea. Use
\r
para regresar al comienzo de la línea sin escribir\n
en la terminal.Escriba
\n
cuando haya terminado para avanzar la línea.Use
echo -ne
para:\n
y\r
.Aquí hay una demostración:
En un comentario a continuación, puk menciona que "falla" si comienza con una línea larga y luego desea escribir una línea corta: en este caso, deberá sobrescribir la longitud de la línea larga (por ejemplo, con espacios).
fuente
printf
lugar deecho
.printf "#### (50%%)\r"
no funcionaría con comillas simples y se debe escapar el signo de porcentaje.También te puede interesar cómo hacer una ruleta :
¿Puedo hacer una ruleta en Bash?
fuente
while :;do for s in / - \\ \|; do printf "\r$s";sleep .1;done;done
(*:sleep
puede requerir entradas en lugar de decimales)some_work ...
línea de arriba; Aquí puede encontrar una discusión más detallada que se basa en esta útil respuesta y el útil comentario de Adam Katz, con un enfoque en el cumplimiento de POSIX .\b
lugar de\r
, ya que de lo contrario solo funcionará al comienzo de una línea:while :; do for c in / - \\ \|; do printf '%s\b' "$c"; sleep 1; done; done
- o, si se muestra el cursor detrás de la ruleta no es deseado:printf ' ' && while :; do for c in / - \\ \|; do printf '\b%s' "$c"; sleep 1; done; done
job=$!
) y luego ejecutarlowhile kill -0 $job 2>/dev/null;do …
, por ejemplo:sleep 15 & job=$!; while kill -0 $job 2>/dev/null; do for s in / - \\ \|; do printf "\r$s"; sleep .1; done; done
Algunas publicaciones han mostrado cómo mostrar el progreso del comando. Para calcularlo, necesitarás ver cuánto has progresado. En los sistemas BSD, algunos comandos, como dd (1), aceptan una
SIGINFO
señal e informarán de su progreso. En los sistemas Linux, algunos comandos responderán de manera similarSIGUSR1
. Si esta función está disponible, puede canalizar su entradadd
para monitorear el número de bytes procesados.Alternativamente, puede utilizar
lsof
para obtener el desplazamiento del puntero de lectura del archivo, y así calcular el progreso. He escrito un comando, llamado pmonitor , que muestra el progreso del procesamiento de un proceso o archivo específico. Con él puedes hacer cosas, como las siguientes.Una versión anterior de los scripts de shell de Linux y FreeBSD aparece en mi blog .
fuente
awk
está en juego!Obtuve una función de barra de progreso fácil que escribí el otro día:
O enganche desde
https://github.com/fearside/ProgressBar/
fuente
printf "\rProgress : [${_fill// /▇}${_empty// / }] ${_progress}%%"
usa el comando linux pv:
http://linux.die.net/man/1/pv
no sabe el tamaño si está en el medio de la transmisión, pero proporciona una velocidad y un total, y desde allí puede calcular cuánto tiempo debería tomar y obtener retroalimentación para que sepa que no se ha colgado.
fuente
Estaba buscando algo más sexy que la respuesta seleccionada, al igual que mi propio guión.
Avance
Fuente
Lo puse en github
progress-bar.sh
Uso
fuente
progress-bar 100
GNU tar tiene una opción útil que brinda la funcionalidad de una barra de progreso simple.
(...) Otra acción de punto de control disponible es 'punto' (o '.'). Le indica a tar que imprima un solo punto en la secuencia de listado estándar, por ejemplo:
El mismo efecto puede ser obtenido por:
fuente
--checkpoint=.10
. También funciona muy bien cuando se extrae contar -xz
.Un método más simple que funciona en mi sistema usando la utilidad pipeview (pv).
fuente
No he visto nada similar y todas las funciones personalizadas aquí parecen centrarse solo en el renderizado, así que ... mi muy simple solución compatible con POSIX a continuación con explicaciones paso a paso porque esta pregunta no es trivial.
TL; DR
Renderizar la barra de progreso es muy fácil. Estimar cuánto debería renderizar es una cuestión diferente. Así es como se representa (anima) la barra de progreso: puede copiar y pegar este ejemplo en un archivo y ejecutarlo:
{1..20}
- valores del 1 al 20echo -n
- imprimir sin nueva línea al finalecho -e
- interpretar caracteres especiales durante la impresión"\r"
- retorno de carro, un carácter especial para volver al comienzo de la líneaPuede hacer que reproduzca cualquier contenido a cualquier velocidad, por lo que este método es muy universal, por ejemplo, se usa a menudo para visualizar "piratería" en películas tontas, no es broma.
Respuesta completa
El meollo del problema es cómo determinar el
$i
valor, es decir, cuánto de la barra de progreso para mostrar. En el ejemplo anterior, simplemente dejé que se incremente enfor
bucle para ilustrar el principio, pero una aplicación de la vida real usaría un bucle infinito y calcularía la$i
variable en cada iteración. Para realizar dicho cálculo necesita los siguientes ingredientes:En caso de
cp
que necesite el tamaño de un archivo fuente y el tamaño del archivo de destino:stat
- verifique las estadísticas del archivo-c
- valor devuelto formateado%s
- tamaño totalEn el caso de operaciones como el desempaquetado de archivos, calcular el tamaño de la fuente es un poco más difícil pero igual de fácil que obtener el tamaño de un archivo sin comprimir:
gzip -l
- muestra información sobre el archivo ziptail -n1
- trabajar con 1 línea desde abajotr -s ' '
- traducir múltiples espacios a uno (exprimirlos)cut -d' ' -f3
- corte la tercera columna delimitada por espaciosAquí está la carne del problema, sin embargo. Esta solución es cada vez menos general. Todos los cálculos del progreso real están estrechamente vinculados al dominio que está tratando de visualizar, es una operación de un solo archivo, una cuenta regresiva del temporizador, un número creciente de archivos en un directorio, operación en múltiples archivos, etc., por lo tanto, No se puede reutilizar. La única parte reutilizable es la representación de la barra de progreso. Para reutilizarlo, debe abstraerlo y guardarlo en un archivo (por ejemplo
/usr/lib/progress_bar.sh
), luego definir funciones que calculen los valores de entrada específicos de su dominio. Así es como podría verse un código generalizado (también hice la$BAR
dinámica porque la gente lo pedía, el resto ya debería estar claro):printf
- un archivo incorporado para imprimir cosas en un formato dadoprintf '%50s'
- no imprima nada, rellene con 50 espaciostr ' ' '#'
- traduce cada espacio al signo hashY así es como lo usarías:
Obviamente, puede envolverse en una función, reescribirse para trabajar con flujos entubados, reescribirse en otro idioma, sea cual sea su veneno.
fuente
También me gustaría contribuir con mi propia barra de progreso
Alcanza la precisión de los subcaracteres utilizando bloques Half Unicode
El código está incluido
fuente
Barra de progreso de estilo APT (no rompe la salida normal)
EDITAR: para obtener una versión actualizada, consulte mi página de github
No estaba satisfecho con las respuestas a esta pregunta. Lo que estaba buscando personalmente era una barra de progreso elegante como lo ve APT.
Eché un vistazo al código fuente C de APT y decidí escribir mi propio equivalente para bash.
Esta barra de progreso permanecerá bien en la parte inferior del terminal y no interferirá con ninguna salida enviada al terminal.
Tenga en cuenta que la barra está actualmente fija en 100 caracteres de ancho. Si desea escalarlo al tamaño del terminal, esto también es bastante fácil de lograr (la versión actualizada en mi página de github lo maneja bien).
Publicaré mi guión aquí. Ejemplo de uso:
El script (recomiendo la versión en mi github):
fuente
Esto le permite visualizar que un comando aún se está ejecutando:
Esto creará un ciclo while infinito que se ejecuta en segundo plano y hace eco de un "." cada segundo. Esto se mostrará
.
en el shell. Ejecute eltar
comando o cualquier comando que desee. Cuando ese comando termine de ejecutarse, elimine el último trabajo que se ejecuta en segundo plano, que es el ciclo while infinito .fuente
Así es como podría verse
Subiendo un archivo
A la espera de un trabajo para completar
Función simple que lo implementa
Puedes copiarlo y pegarlo en tu script. No requiere nada más para funcionar.
Ejemplo de uso
Aquí, cargamos un archivo y redibujamos la barra de progreso en cada iteración. No importa qué trabajo se realice realmente siempre que podamos obtener 2 valores: valor máximo y valor actual.
En el siguiente ejemplo, el valor máximo es
file_size
y el valor actual es suministrado por alguna función y se llamauploaded_bytes
.fuente
La mayoría de los comandos de Unix no le darán el tipo de retroalimentación directa de la que puede hacer esto. Algunos le darán salida en stdout o stderr que puede usar.
Para algo como tar, podría usar el modificador -v y canalizar la salida a un programa que actualice una pequeña animación para cada línea que lea. A medida que el tar escribe una lista de archivos, el programa puede actualizar la animación. Para completar un porcentaje, debe conocer la cantidad de archivos y contar las líneas.
cp no da este tipo de salida por lo que yo sé. Para monitorear el progreso de cp, debería monitorear los archivos de origen y de destino y observar el tamaño del destino. Puede escribir un pequeño programa en C utilizando la llamada al sistema stat (2) para obtener el tamaño del archivo. Esto leería el tamaño de la fuente, luego sondearía el archivo de destino y actualizaría una barra de% completado en función del tamaño del archivo escrito hasta la fecha.
fuente
Mi solución muestra el porcentaje del tarball que actualmente se está descomprimiendo y escribiendo. Lo uso cuando escribo imágenes de sistema de archivos raíz de 2GB. Realmente necesitas una barra de progreso para estas cosas. Lo que hago es usar
gzip --list
para obtener el tamaño total sin comprimir del tarball. A partir de eso calculo el factor de bloqueo necesario para dividir el archivo en 100 partes. Finalmente, imprimo un mensaje de punto de control para cada bloque. Para un archivo de 2 GB, esto da aproximadamente 10 MB por bloque. Si eso es demasiado grande, puede dividir el BLOCKING_FACTOR por 10 o 100, pero es más difícil imprimir una salida bonita en términos de porcentaje.Suponiendo que está usando Bash, puede usar la siguiente función de shell
fuente
En primer lugar, la barra no es el único medidor de progreso de tubería. El otro (quizás incluso más conocido) es pv (visor de tuberías).
En segundo lugar, bar y pv se pueden usar, por ejemplo, de esta manera:
o incluso:
Un truco útil si desea utilizar bar y pv en comandos que funcionan con archivos dados en argumentos, como por ejemplo, copiar archivo1 archivo2, es usar la sustitución del proceso :
La sustitución de procesos es una cosa mágica que crea archivos temporales de quince tubos / dev / fd / y conecta stdout del proceso ejecutado (dentro del paréntesis) a través de este tubo y la copia lo ve como un archivo ordinario (con una excepción, solo puede leerlo hacia adelante).
Actualizar:
El comando bar también permite copiar. Después del hombre bar:
Pero la sustitución de procesos es, en mi opinión, una forma más genérica de hacerlo. Y usa el propio programa cp.
fuente
Prefiero usar el diálogo con el parámetro --gauge . Se usa muy a menudo en instalaciones de paquetes .deb y otras cosas de configuración básica de muchas distribuciones. Así que no necesitas reinventar la rueda ... otra vez
Simplemente ponga un valor int de 1 a 100 @stdin. Un ejemplo básico y tonto:
Tengo este archivo / bin / Wait (con permisos chmod u + x) para cocinar: P
Entonces puedo poner:
Wait "34 min" "warm up the oven"
o
Wait "dec 31" "happy new year"
fuente
para mí, lo más fácil de usar y lo mejor hasta ahora es el comando
pv
obar
como algún tipo ya escribiópor ejemplo: necesita hacer una copia de seguridad de toda la unidad con
dd
normalmente usas
dd if="$input_drive_path" of="$output_file_path"
con
pv
usted puede hacerlo así:dd if="$input_drive_path" | pv | dd of="$output_file_path"
y el progreso va directamente a
STDOUT
esto:una vez hecho, aparece el resumen
fuente
pv
obar
visualizar el progreso de diferentes procesos, por ejemplo, cuenta regresiva del temporizador, posición en un archivo de texto, instalación de su aplicación, configuración del tiempo de ejecución, etc.?Muchas respuestas describen escribir sus propios comandos para imprimir
'\r' + $some_sort_of_progress_msg
. El problema a veces es que imprimir cientos de estas actualizaciones por segundo ralentizará el proceso.Sin embargo, si alguno de sus procesos produce resultados (por ejemplo,
7z a -r newZipFile myFolder
generará cada nombre de archivo a medida que lo comprime), entonces existe una solución más simple, rápida, indolora y personalizable.Instala el módulo python
tqdm
.Ayuda:
tqdm -h
. Un ejemplo con más opciones:Como beneficio adicional, también puede usar
tqdm
para envolver iterables en código python.https://github.com/tqdm/tqdm/blob/master/README.rst#module
fuente
tqdm
STDOUT awc -l
través de una tubería. Probablemente quieras escapar de eso.tqdm
mostrará el progresoSTDERR
mientras se canaliza su entradaSTDIN
aSTDOUT
. En este casowc -l
recibiría la misma entrada como sitqdm
no estuviera incluida.Basado en el trabajo de Edouard Lopez, creé una barra de progreso que se ajusta al tamaño de la pantalla, sea lo que sea. Echale un vistazo.
También está publicado en Git Hub .
Disfrutar
fuente
https://github.com/extensionsapp/progre.sh
Crea un 40 por ciento de progreso:
progreSh 40
fuente
Esto solo es aplicable usando gnome zenity. Zenity proporciona una excelente interfaz nativa para bash scripts: https://help.gnome.org/users/zenity/stable/
Del ejemplo de la barra de progreso de Zenity:
fuente
Usé una respuesta de Crear una cadena de caracteres repetidos en el script de shell para la repetición de caracteres. Tengo dos versiones bash relativamente pequeñas para los scripts que necesitan mostrar la barra de progreso (por ejemplo, un bucle que atraviesa muchos archivos, pero no es útil para archivos tar grandes o operaciones de copia). La más rápida consta de dos funciones, una para preparar las cadenas para la visualización de la barra:
y uno para mostrar una barra de progreso:
Se podría usar como:
lo que significa preparar cadenas para la barra con 50 caracteres "#", y después de eso:
mostrará el número de caracteres "#" que corresponde a la relación 35/80:
Tenga en cuenta que la función muestra la barra en la misma línea una y otra vez hasta que usted (o algún otro programa) imprima una nueva línea. Si coloca -1 como primer parámetro, la barra se borrará:
La versión más lenta es todo en una función:
y se puede usar como (el mismo ejemplo que el anterior):
Si necesita barra de progreso en stderr, simplemente agregue
>&2
al final de cada comando printf.fuente
Para indicar el progreso de la actividad, pruebe los siguientes comandos:
O
O
O
Uno puede usar banderas / variables dentro del ciclo while para verificar y mostrar el valor / extensión del progreso.
fuente
Utilizando las sugerencias enumeradas anteriormente, decidí implementar mi propia barra de progreso.
fuente
percent_none="$(( 100 - "$percent_done" ))"
apercent_none="$(( 100 - $percent_done))"
Hice una versión de shell pura para un sistema embebido aprovechando:
Función de manejo de señal SIGUSR1 de / usr / bin / dd.
Básicamente, si envía un 'kill SIGUSR1 $ (pid_of_running_dd_process)', generará un resumen de la velocidad de procesamiento y la cantidad transferida.
dd en segundo plano y luego consultarlo regularmente para obtener actualizaciones, y generar marcas de hash como solían hacerlo los clientes ftp de la vieja escuela.
Usando / dev / stdout como el destino para programas amigables no stdout como scp
El resultado final le permite realizar cualquier operación de transferencia de archivos y obtener una actualización de progreso que se parece a la salida 'hash' FTP de la vieja escuela donde solo obtendría una marca hash por cada X bytes.
Este no es un código de calidad de producción, pero ya se entiende la idea. Pienso que es lindo.
Para lo que vale, el recuento de bytes real puede no reflejarse correctamente en el número de hashes; puede tener uno más o menos dependiendo de los problemas de redondeo. No use esto como parte de un guión de prueba, es simplemente atractivo. Y sí, soy consciente de que esto es terriblemente ineficiente: es un script de shell y no me disculpo por ello.
Ejemplos con wget, scp y tftp proporcionados al final. Debería funcionar con cualquier cosa que haya emitido datos. Asegúrese de usar / dev / stdout para programas que no sean compatibles con stdout.
Ejemplos:
fuente
pidof dd
es aterradora.$!
desdedd
y esperar en[[ -e /proc/${DD_PID} ]]
.En caso de que tenga que mostrar una barra de progreso temporal (al conocer de antemano el tiempo de visualización), puede usar Python de la siguiente manera:
Luego, suponiendo que haya guardado el script Python como
progressbar.py
, es posible mostrar la barra de progreso desde su script bash ejecutando el siguiente comando:Mostraría una barra de progreso del tamaño de
50
caracteres y "corriendo" por10
segundos.fuente
Me he basado en la respuesta proporcionada por fearside
Esto se conecta a una base de datos Oracle para recuperar el progreso de una restauración RMAN.
fuente
podría crear una función que dibuje esto en una escala digamos 1-10 para el número de barras:
fuente
salida:
nota: si en lugar de 255 pones 1, monitorearás la entrada estándar ... con 2 la salida estándar (pero debes modificar la fuente para establecer "tot" al tamaño de archivo de salida proyectado)
fuente