sentencias scripts script que programar programacion hacer ejemplos ejemplo control como comandos bash shell zsh

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



sentencias de control en shell script (30)

Al ejecutar scripts en bash o cualquier otro shell en * NIX, al ejecutar un comando que llevará más de unos pocos segundos, se necesita una barra de progreso.

Por ejemplo, copiando un archivo grande, abriendo un archivo tar grande.

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


Aquí es cómo podría verse

Subiendo un archivo

[##################################################] 100% (137921 / 137921 bytes)

Esperando un trabajo para completar

[######################### ] 50% (15 / 30 seconds)

Función simple que la implementa.

Puedes copiarlo y pegarlo en tu script. No requiere nada más para trabajar.

PROGRESS_BAR_WIDTH=50 # progress bar length in characters draw_progress_bar() { # Arguments: current value, max value, unit of measurement (optional) local __value=$1 local __max=$2 local __unit=${3:-""} # if unit is not supplied, do not display it # Calculate percentage if (( $__max < 1 )); then __max=1; fi # anti zero division protection local __percentage=$(( 100 - ($__max*100 - $__value*100) / $__max )) # Rescale the bar according to the progress bar width local __num_bar=$(( $__percentage * $PROGRESS_BAR_WIDTH / 100 )) # Draw progress bar printf "[" for b in $(seq 1 $__num_bar); do printf "#"; done for s in $(seq 1 $(( $PROGRESS_BAR_WIDTH - $__num_bar ))); do printf " "; done printf "] $__percentage%% ($__value / $__max $__unit)/r" }

Ejemplo de uso

Aquí, cargamos un archivo y volvemos a dibujar 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 lo proporciona alguna función y se llama uploaded_bytes .

# Uploading a file file_size=137921 while true; do # Get current value of uploaded bytes uploaded_bytes=$(some_function_that_reports_progress) # Draw a progress bar draw_progress_bar $uploaded_bytes $file_size "bytes" # Check if we reached 100% if [ $uploaded_bytes == $file_size ]; then break; fi sleep 1 # Wait before redrawing done # Go to the newline at the end of upload printf "/n"


Algunas publicaciones han mostrado cómo mostrar el progreso del comando. Para calcularlo, deberás ver cuánto has progresado. En los sistemas BSD, algunos comandos, como dd (1), aceptan una señal SIGINFO e informarán sobre su progreso. En los sistemas Linux, algunos comandos responderán de manera similar a SIGUSR1 . Si esta instalación está disponible, puede canalizar su entrada a través de dd para monitorear el número de bytes procesados.

Alternativamente, puede usar 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.

$ pmonitor -c gzip /home/dds/data/mysql-2015-04-01.sql.gz 58.06%

Una versión anterior de los scripts de shell de Linux y FreeBSD aparece en mi blog .


Basándome en el trabajo de Edouard López, creé una barra de progreso que se ajusta al tamaño de la pantalla, sea cual sea. Echale un vistazo.

También está publicado en Git Hub .

#!/bin/bash # # Progress bar by Adriano Pinaffo # Available at https://github.com/adriano-pinaffo/progressbar.sh # Inspired on work by Edouard Lopez (https://github.com/edouard-lopez/progress-bar.sh) # Version 1.0 # Date April, 28th 2017 function error { echo "Usage: $0 [SECONDS]" case $1 in 1) echo "Pass one argument only" exit 1 ;; 2) echo "Parameter must be a number" exit 2 ;; *) echo "Unknown error" exit 999 esac } [[ $# -ne 1 ]] && error 1 [[ $1 =~ ^[0-9]+$ ]] || error 2 duration=${1} barsize=$((`tput cols` - 7)) unity=$(($barsize / $duration)) increment=$(($barsize%$duration)) skip=$(($duration/($duration-$increment))) curr_bar=0 prev_bar= for (( elapsed=1; elapsed<=$duration; elapsed++ )) do # Elapsed prev_bar=$curr_bar let curr_bar+=$unity [[ $increment -eq 0 ]] || { [[ $skip -eq 1 ]] && { [[ $(($elapsed%($duration/$increment))) -eq 0 ]] && let curr_bar++; } || { [[ $(($elapsed%$skip)) -ne 0 ]] && let curr_bar++; } } [[ $elapsed -eq 1 && $increment -eq 1 && $skip -ne 1 ]] && let curr_bar++ [[ $(($barsize-$curr_bar)) -eq 1 ]] && let curr_bar++ [[ $curr_bar -lt $barsize ]] || curr_bar=$barsize for (( filled=0; filled<=$curr_bar; filled++ )); do printf "▇" done # Remaining for (( remain=$curr_bar; remain<$barsize; remain++ )); do printf " " done # Percentage printf "| %s%%" $(( ($elapsed*100)/$duration)) # Return sleep 1 printf "/r" done printf "/n" exit 0

Disfrutar


En caso de que tenga que mostrar una barra de progreso temporal (sabiendo de antemano el tiempo de visualización), puede usar Python de la siguiente manera:

#!/bin/python from time import sleep import sys if len(sys.argv) != 3: print "Usage:", sys.argv[0], "<total_time>", "<progressbar_size>" exit() TOTTIME=float(sys.argv[1]) BARSIZE=float(sys.argv[2]) PERCRATE=100.0/TOTTIME BARRATE=BARSIZE/TOTTIME for i in range(int(TOTTIME)+1): sys.stdout.write(''/r'') s = "[%-"+str(int(BARSIZE))+"s] %d%% " sys.stdout.write(s % (''=''*int(BARRATE*i), int(PERCRATE*i))) sys.stdout.flush() SLEEPTIME = 1.0 if i == int(TOTTIME): SLEEPTIME = 0.1 sleep(SLEEPTIME) print ""

Luego, asumiendo que guardó el script Python como progressbar.py , es posible mostrar la barra de progreso desde su script bash ejecutando el siguiente comando:

python progressbar.py 10 50

Mostraría una barra de progreso con un tamaño de 50 caracteres y "correr" durante 10 segundos.


En primer lugar, Bar no es el único medidor de progreso de tubería. El otro (tal vez incluso más conocido) es pv (visor de tuberías).

En segundo lugar, bar y pv se pueden usar, por ejemplo, de esta manera:

$ bar file1 | wc -l $ pv file1 | wc -l

o incluso:

$ tail -n 100 file1 | bar | wc -l $ tail -n 100 file1 | pv | wc -l

Un truco útil si desea utilizar bar y pv en comandos que trabajan con archivos dados en argumentos, como por ejemplo copiar archivo1 archivo2, es usar la sustitución de procesos :

$ copy <(bar file1) file2 $ copy <(pv file1) file2

La sustitución de procesos es una cosa de magia bash que crea archivos de pipe / dev / fd / fifo temporales y conecta la salida estándar del proceso ejecutado (entre paréntesis) a través de este pipe y copy lo ve como un archivo ordinario (con una excepción, solo puede leerlo hacia adelante).

Actualizar:

El propio comando de barra permite también copiar. Después de la barra de hombre:

bar --in-file /dev/rmt/1cbn --out-file / tape-restore.tar --size 2.4g --buffer-size 64k

Pero la sustitución de procesos es, en mi opinión, una forma más genérica de hacerlo. Un programa usa el propio cp.


Estaba buscando algo más sexy que la respuesta seleccionada, también lo hizo mi propio guión.

Avance

Fuente

Lo puse en github progress-bar.sh

progress-bar() { local duration=${1} already_done() { for ((done=0; done<$elapsed; done++)); do printf "▇"; done } remaining() { for ((remain=$elapsed; remain<$duration; remain++)); do printf " "; done } percentage() { printf "| %s%%" $(( (($elapsed)*100)/($duration)*100/100 )); } clean_line() { printf "/r"; } for (( elapsed=1; elapsed<=$duration; elapsed++ )); do already_done; remaining; percentage sleep 1 clean_line done clean_line }

Uso

progress-bar 100


Esto le permite visualizar que un comando todavía se está ejecutando:

while :;do echo -n .;sleep 1;done & trap "kill $!" EXIT #Die with parent if we die prematurely tar zxf packages.tar.gz; # or any other command here kill $! && trap " " EXIT #Kill the loop and unset the trap or else the pid might get reassigned and we might end up killing a completely different process

Esto creará un bucle while infinito que se ejecuta en segundo plano y hace eco de un "." cada segundo. Esto se mostrará . en la concha Ejecute el comando tar o cualquier comando que desee. Cuando ese comando termina de ejecutarse, finalice el último trabajo que se ejecuta en segundo plano, que es el bucle infinito while .


Esto solo es aplicable usando gnome zenity. Zenity proporciona una excelente interfaz nativa para bash scripts: https://help.gnome.org/users/zenity/stable/

Ejemplo de la barra de progreso de Zenity:

#!/bin/sh ( echo "10" ; sleep 1 echo "# Updating mail logs" ; sleep 1 echo "20" ; sleep 1 echo "# Resetting cron jobs" ; sleep 1 echo "50" ; sleep 1 echo "This line will just be ignored" ; sleep 1 echo "75" ; sleep 1 echo "# Rebooting system" ; sleep 1 echo "100" ; sleep 1 ) | zenity --progress / --title="Update System Logs" / --text="Scanning mail logs..." / --percentage=0 if [ "$?" = -1 ] ; then zenity --error / --text="Update canceled." fi


He construido sobre la respuesta proporcionada por el miedo

Esto se conecta a una base de datos Oracle para recuperar el progreso de una restauración RMAN.

#!/bin/bash # 1. Create ProgressBar function # 1.1 Input is currentState($1) and totalState($2) function ProgressBar { # Process data let _progress=(${1}*100/${2}*100)/100 let _done=(${_progress}*4)/10 let _left=40-$_done # Build progressbar string lengths _fill=$(printf "%${_done}s") _empty=$(printf "%${_left}s") # 1.2 Build progressbar strings and print the ProgressBar line # 1.2.1 Output example: # 1.2.1.1 Progress : [########################################] 100% printf "/rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%" } function rman_check { sqlplus -s / as sysdba <<EOF set heading off set feedback off select round((sofar/totalwork) * 100,0) pct_done from v/$session_longops where totalwork > sofar AND opname NOT LIKE ''%aggregate%'' AND opname like ''RMAN%''; exit EOF } # Variables _start=1 # This accounts as the "totalState" variable for the ProgressBar function _end=100 _rman_progress=$(rman_check) #echo ${_rman_progress} # Proof of concept #for number in $(seq ${_start} ${_end}) while [ ${_rman_progress} -lt 100 ] do for number in _rman_progress do sleep 10 ProgressBar ${number} ${_end} done _rman_progress=$(rman_check) done printf ''/nFinished!/n''


Hice una versión de shell puro para un sistema integrado aprovechando:

  • La 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)'', obtendrá un resumen de la velocidad de procesamiento y la cantidad transferida.

  • en segundo plano dd y luego consultándolo regularmente para actualizaciones, y generando tic tac de hash como solían hacer los clientes ftp de la vieja escuela.

  • Usando / dev / stdout como 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 de "hash" del FTP de la vieja escuela, donde solo obtendría una marca de control por cada X bytes.

Esto no es un código de calidad de producción, pero entiendes la idea. Pienso que es lindo.

Para lo que vale, el número real de bytes no se refleja correctamente en el número de hashes; es posible que tenga uno más o menos según los problemas de redondeo. No utilices esto como parte de un guión de prueba, es solo una sorpresa. 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 al final. Debería funcionar con cualquier cosa que tenga datos emitados. Asegúrate de usar / dev / stdout para programas que no sean amigables con stdout.

#!/bin/sh # # Copyright (C) Nathan Ramella ([email protected]) 2010 # LGPLv2 license # If you use this, send me an email to say thanks and let me know what your product # is so I can tell all my friends I''m a big man on the internet! progress_filter() { local START=$(date +"%s") local SIZE=1 local DURATION=1 local BLKSZ=51200 local TMPFILE=/tmp/tmpfile local PROGRESS=/tmp/tftp.progress local BYTES_LAST_CYCLE=0 local BYTES_THIS_CYCLE=0 rm -f ${PROGRESS} dd bs=$BLKSZ of=${TMPFILE} 2>&1 / | grep --line-buffered -E ''[[:digit:]]* bytes'' / | awk ''{ print $1 }'' >> ${PROGRESS} & # Loop while the ''dd'' exists. It would be ''more better'' if we # actually looked for the specific child ID of the running # process by identifying which child process it was. If someone # else is running dd, it will mess things up. # My PID handling is dumb, it assumes you only have one running dd on # the system, this should be fixed to just get the PID of the child # process from the shell. while [ $(pidof dd) -gt 1 ]; do # PROTIP: You can sleep partial seconds (at least on linux) sleep .5 # Force dd to update us on it''s progress (which gets # redirected to $PROGRESS file. # # dumb pid handling again pkill -USR1 dd local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS) local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ)) # Don''t print anything unless we''ve got 1 block or more. # This allows for stdin/stderr interactions to occur # without printing a hash erroneously. # Also makes it possible for you to background ''scp'', # but still use the /dev/stdout trick _even_ if scp # (inevitably) asks for a password. # # Fancy! if [ $XFER_BLKS -gt 0 ]; then printf "#%0.s" $(seq 0 $XFER_BLKS) BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE fi done local SIZE=$(stat -c"%s" $TMPFILE) local NOW=$(date +"%s") if [ $NOW -eq 0 ]; then NOW=1 fi local DURATION=$(($NOW-$START)) local BYTES_PER_SECOND=$(( SIZE / DURATION )) local KBPS=$((SIZE/DURATION/1024)) local MD5=$(md5sum $TMPFILE | awk ''{ print $1 }'') # This function prints out ugly stuff suitable for eval() # rather than a pretty string. This makes it a bit more # flexible if you have a custom format (or dare I say, locale?) printf "/nDURATION=%d/nBYTES=%d/nKBPS=%f/nMD5=%s/n" / $DURATION / $SIZE / $KBPS / $MD5 }

Ejemplos:

echo "wget" wget -q -O /dev/stdout http://www.blah.com/somefile.zip | progress_filter echo "tftp" tftp -l /dev/stdout -g -r something/firmware.bin 192.168.1.1 | progress_filter echo "scp" scp [email protected]:~/myfile.tar /dev/stdout | progress_filter


La mayoría de los comandos de Unix no te darán el tipo de retroalimentación directa desde la que puedes hacer esto. Algunos te darán salida en stdout o stderr que puedes usar.

Para algo como tar, puede usar el interruptor -v y canalizar la salida a un programa que actualiza una pequeña animación para cada línea que lee. A medida que tar escribe una lista de archivos, el programa puede actualizar la animación. Para completar un porcentaje, deberías saber la cantidad de archivos y contar las líneas.

cp no da este tipo de salida por lo que sé. Para monitorear el progreso de cp, tendría que monitorear los archivos de origen y destino y ver el tamaño del destino. Puede escribir un programa c pequeño usando la llamada al sistema stat (2) para obtener el tamaño del archivo. Esto leería el tamaño del origen, luego sondearía el archivo de destino y actualizaría una barra de% completa en función del tamaño del archivo escrito hasta la fecha.


Mi solución muestra el porcentaje de tarball que actualmente se está descomprimiendo y escribiendo. Uso esto 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 archivo comprimido. 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 2GB esto da aproximadamente 10MB por bloque. Si eso es demasiado grande, puede dividir BLOCKING_FACTOR por 10 o 100, pero luego es más difícil imprimir una buena cantidad en términos de porcentaje.

Asumiendo que está utilizando Bash, entonces puede usar la siguiente función de shell

untar_progress () { TARBALL=$1 BLOCKING_FACTOR=$(gzip --list ${TARBALL} | perl -MPOSIX -ane ''$.==2 && print ceil $F[1]/50688'') tar --blocking-factor=${BLOCKING_FACTOR} --checkpoint=1 / --checkpoint-action=''ttyout=Wrote %u% /r'' -zxf ${TARBALL} }


Muchas respuestas describen cómo 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 emitirá cada nombre de archivo a medida que lo comprima), entonces existe una solución más simple, rápida, indolora y personalizable.

Instale el módulo python tqdm .

$ sudo pip install tqdm $ # now have fun $ 7z a -r -bd newZipFile myFolder | tqdm >> /dev/null $ # if we know the expected total, we can have a bar! $ 7z a -r -bd newZipFile myFolder | grep -o Compressing | tqdm --total $(find myFolder -type f | wc -l) >> /dev/null

Ayuda: tqdm -h . Un ejemplo usando más opciones:

$ find / -name ''*.py'' -exec cat /{} /; | tqdm --unit loc --unit_scale True | wc -l

Como tqdm adicional, también puede usar tqdm para envolver iterables en código python.

https://github.com/tqdm/tqdm/blob/master/README.rst#module


No he visto nada similar así que ... mi solución muy simple:

#!/bin/bash BAR=''####################'' # this is full bar, mine is 20 chars for i in {1..20}; do echo -ne "/r${BAR:0:$i}" # print $i chars of $BAR from 0 position sleep .1 done

  • echo -n - imprimir sin nueva línea al final
  • echo -e - interpreta caracteres especiales al imprimir
  • "/r" - retorno de carro, un carácter especial para volver al principio de la línea

Lo usé hace mucho tiempo en un simple "video de piratería" para simular el código de escritura. ;)


Para indicar el progreso de la actividad, pruebe los siguientes comandos:

while true; do sleep 0.25 && echo -ne "/r//" && sleep 0.25 && echo -ne "/r|" && sleep 0.25 && echo -ne "/r/" && sleep 0.25 && echo -ne "/r-"; done;

O

while true; do sleep 0.25 && echo -ne "/rActivity: //" && sleep 0.25 && echo -ne "/rActivity: |" && sleep 0.25 && echo -ne "/rActivity: /" && sleep 0.25 && echo -ne "/rActivity: -"; done;

O

while true; do sleep 0.25 && echo -ne "/r" && sleep 0.25 && echo -ne "/r>" && sleep 0.25 && echo -ne "/r>>" && sleep 0.25 && echo -ne "/r>>>"; sleep 0.25 && echo -ne "/r>>>>"; done;

O

while true; do sleep .25 && echo -ne "/r:Active:" && sleep .25 && echo -ne "/r:aCtive:" && sleep .25 && echo -ne "/r:acTive:" && sleep .25 && echo -ne "/r:actIve:" && sleep .25 && echo -ne "/r:actiVe:" && sleep .25 && echo -ne "/r:activE:"; done;

Se pueden usar indicadores / variables dentro del bucle while para verificar y mostrar el valor / grado del progreso.


Para mí, el más fácil de usar y el que más se ve es el comando pv o el bar como lo escribió un chico

por ejemplo: necesita hacer una copia de seguridad de todo el disco con dd

normalmente usas dd if="$input_drive_path" of="$output_file_path"

con pv puedes hacerlo así:

dd if="$input_drive_path" | pv | dd of="$output_file_path"

y el progreso va directamente a STDOUT como esto:

7.46GB 0:33:40 [3.78MB/s] [ <=> ]

después de que se hace el resumen aparece

15654912+0 records in 15654912+0 records out 8015314944 bytes (8.0 GB) copied, 2020.49 s, 4.0 MB/s


Prefiero usar el diálogo con el parámetro --gauge . Se usa muy a menudo en las 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:

for a in {1..100}; do sleep .1s; echo $a| dialog --gauge "waiting" 7 30; done

Tengo este / bin / Wait file (con chmod u + x perms) para cocinar: P

#!/bin/bash INIT=`/bin/date +%s` NOW=$INIT FUTURE=`/bin/date -d "$1" +%s` [ $FUTURE -a $FUTURE -eq $FUTURE ] || exit DIFF=`echo "$FUTURE - $INIT"|bc -l` while [ $INIT -le $FUTURE -a $NOW -lt $FUTURE ]; do NOW=`/bin/date +%s` STEP=`echo "$NOW - $INIT"|bc -l` SLEFT=`echo "$FUTURE - $NOW"|bc -l` MLEFT=`echo "scale=2;$SLEFT/60"|bc -l` TEXT="$SLEFT seconds left ($MLEFT minutes)"; TITLE="Waiting $1: $2" sleep 1s PTG=`echo "scale=0;$STEP * 100 / $DIFF"|bc -l` echo $PTG| dialog --title "$TITLE" --gauge "$TEXT" 7 72 done if [ "$2" == "" ]; then msg="Espera terminada: $1";audio="Listo"; else msg=$2;audio=$2;fi /usr/bin/notify-send --icon=stock_appointment-reminder-excl "$msg" espeak -v spanish "$audio"

Así que puedo poner:

Wait "34 min" "warm up the oven"

o

Wait "dec 31" "happy new year"



También te puede interesar cómo hacer una ruleta :

¿Puedo hacer un spinner en Bash?

¡Por supuesto!

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, envolviéndolo cuando llega al final. (i es la posición del carácter actual a mostrar y $ {# sp} es la longitud de la cadena sp).

La cadena / b se reemplaza por un carácter ''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 de 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 de giro:

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


Tengo una función de barra de progreso fácil que escribí el otro día:

#!/bin/bash # 1. Create ProgressBar function # 1.1 Input is currentState($1) and totalState($2) function ProgressBar { # Process data let _progress=(${1}*100/${2}*100)/100 let _done=(${_progress}*4)/10 let _left=40-$_done # Build progressbar string lengths _fill=$(printf "%${_done}s") _empty=$(printf "%${_left}s") # 1.2 Build progressbar strings and print the ProgressBar line # 1.2.1 Output example: # 1.2.1.1 Progress : [########################################] 100% printf "/rProgress : [${_fill// //#}${_empty// /-}] ${_progress}%%" } # Variables _start=1 # This accounts as the "totalState" variable for the ProgressBar function _end=100 # Proof of concept for number in $(seq ${_start} ${_end}) do sleep 0.1 ProgressBar ${number} ${_end} done printf ''/nFinished!/n''

O quítatelo,
https://github.com/fearside/ProgressBar/


Un método más simple que funciona en mi sistema usando la utilidad pipeview (pv).

srcdir=$1 outfile=$2 tar -Ocf - $srcdir | pv -i 1 -w 50 -berps `du -bs $srcdir | awk ''{print $1}''` | 7za a -si $outfile


Usando las sugerencias enumeradas anteriormente, decidí implementar mi propia barra de progreso.

#!/usr/bin/env bash main() { for (( i = 0; i <= 100; i=$i + 20)); do progress_bar "$i" sleep 1; done progress_bar "done" exit 0 } progress_bar() { if [ "$1" == "done" ]; then spinner="X" percent_done="100" progress_message="Done!" new_line="/n" else spinner=''/-/|'' percent_done="${1:-0}" progress_message="$percent_done %" fi percent_none="$(( 100 - "$percent_done" ))" [ "$percent_done" -gt 0 ] && local done_bar="$(printf ''#%.0s'' $(seq -s '' '' 1 $percent_done))" [ "$percent_none" -gt 0 ] && local none_bar="$(printf ''~%.0s'' $(seq -s '' '' 1 $percent_none))" # print the progress bar to the screen printf "/r Progress: [%s%s] %s %s${new_line}" / "$done_bar" / "$none_bar" / "${spinner:x++%${#spinner}:1}" / "$progress_message" } main "$@"


Utilicé una respuesta de Creación de cadenas de caracteres repetidos en el script de shell para la repetición de caracteres. Tengo dos versiones de bash relativamente pequeñas para scripts que necesitan mostrar la barra de progreso (por ejemplo, un bucle que atraviesa muchos archivos, pero no es útil para grandes archivos de alquitrán u operaciones de copia). La más rápida consta de dos funciones, una para preparar las cadenas para la visualización de la barra:

preparebar() { # $1 - bar length # $2 - bar char barlen=$1 barspaces=$(printf "%*s" "$1") barchars=$(printf "%*s" "$1" | tr '' '' "$2") }

y uno para mostrar una barra de progreso:

progressbar() { # $1 - number (-1 for clearing the bar) # $2 - max number if [ $1 -eq -1 ]; then printf "/r $barspaces/r" else barch=$(($1*barlen/$2)) barsp=$((barlen-barch)) printf "/r[%.${barch}s%.${barsp}s]/r" "$barchars" "$barspaces" fi }

Podría ser utilizado como:

preparebar 50 "#"

lo que significa preparar cadenas para la barra con 50 "#" caracteres, y después de eso:

progressbar 35 80

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ía:

progressbar -1 80

La versión más lenta es todo en una función:

progressbar() { # $1 - number # $2 - max number # $3 - number of ''#'' characters if [ $1 -eq -1 ]; then printf "/r %*s/r" "$3" else i=$(($1*$3/$2)) j=$(($3-i)) printf "/r[%*s" "$i" | tr '' '' ''#'' printf "%*s]/r" "$j" fi }

y se puede usar como (el mismo ejemplo anterior):

progressbar 35 80 50

Si necesita la barra de progreso en stderr, simplemente agregue >&2 al final de cada comando printf.


usa el comando linux pv:

http://linux.die.net/man/1/pv

no sabe el tamaño si está en el medio de la secuencia, pero le da una velocidad y total y, a partir de ahí, puede determinar cuánto tiempo debería tardar y obtener retroalimentación para que sepa que no se ha colgado.


GNU tar tiene una opción útil que le da una 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 el flujo de listado estándar, por ejemplo:

$ tar -c --checkpoint=1000 --checkpoint-action=dot /var ...

El mismo efecto puede ser obtenido por:

$ tar -c --checkpoint=.1000 /var


Primero ejecute el proceso en segundo plano, luego observe que se está ejecutando con frecuencia, imprima el patrón y nuevamente verifique si el estado se está ejecutando o no;

Utilizando bucle while para ver el estado del proceso con frecuencia.

use el comando pgrep o cualquier otro comando para ver y obtener el estado de ejecución de un proceso.

si usa pgrep, redirija la salida innecesaria a / dev / null según sea necesario.

Código:

sleep 12& while pgrep sleep &> /dev/null;do echo -en "#";sleep 0.5;done

Este "#" se imprimirá hasta que finalice la suspensión, este método se utiliza para implementar la barra de progreso para el tiempo de progreso del programa.

También puede usar este método para los comandos de shell para analizar el tiempo de proceso como visual.

ERROR: este método pgrep no funciona en todas las situaciones, inesperadamente el otro proceso se estaba ejecutando con el mismo nombre, el bucle while no termina.

por lo tanto, al obtener el estado de ejecución del proceso, especifique su PID, utilizando el comando puede estar disponible con algunos comandos,

el comando ps a listará todo el proceso con id, necesita grep para encontrar el pid del proceso especificado


Puede implementar esto sobrescribiendo una línea. Use /r para volver al principio de la línea sin escribir /n en el terminal.

Escribe /n cuando hayas terminado para avanzar en la línea.

Utilice echo -ne para:

  1. no imprimir /n
  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, deberá sobrescribir la longitud de la línea larga (por ejemplo, con espacios).


Quería hacer un seguimiento del progreso en función del número de líneas que un comando genera contra un número objetivo de líneas de una ejecución anterior:

#!/bin/bash function lines { local file=$1 local default=$2 if [[ -f $file ]]; then wc -l $file | awk ''{print $1}''; else echo $default fi } function bar { local items=$1 local total=$2 local size=$3 percent=$(($items*$size/$total % $size)) left=$(($size-$percent)) chars=$(local s=$(printf "%${percent}s"); echo "${s// /=}") echo -ne "[$chars>"; printf "%${left}s" echo -ne '']/r'' } function clearbar { local size=$1 printf " %${size}s " echo -ne "/r" } function progress { local pid=$1 local total=$2 local file=$3 bar 0 100 50 while [[ "$(ps a | awk ''{print $1}'' | grep $pid)" ]]; do bar $(lines $file 0) $total 50 sleep 1 done clearbar 50 wait $pid return $? }

Entonces úsalo así:

target=$(lines build.log 1000) (mvn clean install > build.log 2>&1) & progress $! $target build.log

Da salida a una barra de progreso que se parece a esto:

[===============================================> ]

La barra crece a medida que el número de líneas de salida alcanza el objetivo. Si el número de líneas supera el objetivo, la barra comienza de nuevo (con suerte, el objetivo es bueno).

Por cierto: estoy usando bash en Mac OSX. mariascio este código en un spinner de mariascio .


Esta es una barra de progreso psicodélico para las secuencias de comandos bash de nExace. Se puede llamar desde la línea de comandos como ''./progressbar xy'' donde ''x'' es un tiempo en segundos y ''y'' es un mensaje asociado con esa parte del progreso.

La función de barra de progreso interna () en sí misma es buena independiente también si quiere que otras partes de su script controlen la barra de progreso. Por ejemplo, enviando ''barra de progreso 10 "Creando el árbol de directorios";'' mostrará:

[####### ] (10%) Creating directory tree

Por supuesto que será bien psicodélico aunque ...

#!/bin/bash if [ "$#" -eq 0 ]; then echo "x is /"time in seconds/" and z is /"message/""; echo "Usage: progressbar x z"; exit; fi progressbar() { local loca=$1; local loca2=$2; declare -a bgcolors; declare -a fgcolors; for i in {40..46} {100..106}; do bgcolors+=("$i") done for i in {30..36} {90..96}; do fgcolors+=("$i") done local u=$(( 50 - loca )); local y; local t; local z; z=$(printf ''%*s'' "$u"); local w=$(( loca * 2 )); local bouncer=".oO°Oo."; for ((i=0;i<loca;i++)); do t="${bouncer:((i%${#bouncer})):1}" bgcolor="//E[${bgcolors[RANDOM % 14]}m //033[m" y+="$bgcolor"; done fgcolor="//E[${fgcolors[RANDOM % 14]}m" echo -ne " $fgcolor$t$y$z$fgcolor$t //E[96m(//E[36m$w%//E[96m)//E[92m $fgcolor$loca2//033[m/r" }; timeprogress() { local loca="$1"; local loca2="$2"; loca=$(bc -l <<< scale=2/;"$loca/50") for i in {1..50}; do progressbar "$i" "$loca2"; sleep "$loca"; done printf "/n" }; timeprogress "$1" "$2"


#!/bin/bash function progress_bar() { bar="" total=10 [[ -z $1 ]] && input=0 || input=${1} x="##" for i in `seq 1 10`; do if [ $i -le $input ] ;then bar=$bar$x else bar="$bar " fi done #pct=$((200*$input/$total % 2 + 100*$input/$total)) pct=$(($input*10)) echo -ne "Progress : [ ${bar} ] (${pct}%) /r" sleep 1 if [ $input -eq 10 ] ;then echo -ne ''/n'' fi }

podría crear una función que dibuje esto en una escala, por ejemplo, 1-10 para el número de barras:

progress_bar 1 echo "doing something ..." progress_bar 2 echo "doing something ..." progress_bar 3 echo "doing something ..." progress_bar 8 echo "doing something ..." progress_bar 10