Comment append une barre de progression à un script shell?

Lors de l’exécution d’un script dans bash ou tout autre shell dans * NIX, lors de l’exécution d’une commande qui prendra plus de quelques secondes, une barre de progression est nécessaire.

Par exemple, copier un gros fichier en ouvrant un gros fichier tar.

Comment recommandez-vous d’append des barres de progression aux scripts shell?

Related of "Comment append une barre de progression à un script shell?"

Vous pouvez l’implémenter en écrasant une ligne. Utilisez \r pour revenir au début de la ligne sans écrire \n au terminal.

Ecrivez \n quand vous avez fini de faire avancer la ligne.

Utilisez echo -ne pour:

  1. pas imprimer \n et
  2. reconnaître les séquences d’échappement comme \r .

Voici une démo:

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

Vous pouvez également être intéressé par la façon de faire un spinner :

Puis-je faire une roulette à Bash?

Sûr!

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

Chaque fois que la boucle est itérée, elle affiche le caractère suivant dans la chaîne de caractères sp (i est la position du caractère actuel à afficher et $ {# sp} est la longueur de la chaîne sp).

La chaîne \ b est remplacée par un caractère “retour arrière”. Vous pouvez également jouer avec \ r pour revenir au début de la ligne.

Si vous voulez qu’il ralentisse, placez une commande de veille dans la boucle (après le printf).

Un équivalent POSIX serait:

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

Si vous avez déjà une boucle qui fait beaucoup de travail, vous pouvez appeler la fonction suivante au début de chaque itération pour mettre à jour le compteur:

 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 

Certains messages ont montré comment afficher la progression de la commande. Pour le calculer, vous devez voir combien vous avez progressé. Sur les systèmes BSD, certaines commandes, telles que dd (1), acceptent un signal SIGINFO et signaleront leur progression. Sur les systèmes Linux, certaines commandes répondront de manière similaire à SIGUSR1 . Si cette fonction est disponible, vous pouvez diriger votre entrée via dd pour surveiller le nombre d’octets traités.

Vous pouvez également utiliser lsof pour obtenir le décalage du pointeur de lecture du fichier et calculer ainsi la progression. J’ai écrit une commande, nommée pmonitor , qui affiche la progression du traitement d’un processus ou d’un fichier spécifié. Avec cela, vous pouvez faire des choses telles que les suivantes.

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

Une version antérieure des scripts shell Linux et FreeBSD apparaît sur mon blog .

utilisez la commande linux pv:

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

il ne connaît pas la taille s’il est au milieu du stream, mais il donne une vitesse et un total et à partir de là vous pouvez déterminer combien de temps cela devrait prendre et obtenir des commentaires pour que vous sachiez qu’il n’a pas été bloqué.

Vous avez une fonction de barre de progression facile que j’ai écrite l’autre jour:

 #!/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 ssortingng lengths _fill=$(printf "%${_done}s") _empty=$(printf "%${_left}s") # 1.2 Build progressbar ssortingngs 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' 

Ou le casser,
https://github.com/fearside/ProgressBar/

GNU tar a une option utile qui donne une fonctionnalité d’une simple barre de progression.

(…) Une autre action de sharepoint contrôle disponible est «point» (ou «.»). Il demande à tar d’imprimer un seul point sur le stream de liste standard, par exemple:

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

Le même effet peut être obtenu par:

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

Je cherchais quelque chose de plus sexy que la réponse choisie, tout comme mon propre script.

Aperçu

progress-bar.sh en action

La source

Je l’ai mis sur 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 } 

Usage

  progress-bar 100 

Une méthode plus simple qui fonctionne sur mon système en utilisant l’utilitaire 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 

Je voudrais aussi consortingbuer ma propre barre de progression

Il permet d’obtenir une précision de sous-caractère en utilisant des blocs demi-unicode

entrer la description de l'image ici

Le code est inclus

Cela vous permet de visualiser qu’une commande est toujours en cours d’exécution:

 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 

Cela créera une boucle while infinie qui s’exécute en arrière-plan et fait écho à un “.” chaque seconde. Cela s’affichera . dans la coquille. Exécutez la commande tar ou toute commande souhaitée. Une fois l’exécution de cette commande terminée, éliminez le dernier travail exécuté en arrière-plan, à savoir la boucle while infinie .

Je n’ai rien vu de semblable alors … ma solution très 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 – imprime sans nouvelle ligne à la fin
  • echo -e – interprète les caractères spéciaux lors de l’impression
  • "\r" – retour chariot, un caractère spécial pour retourner au début de la ligne

Je l’ai utilisé il y a longtemps dans une simple “vidéo de piratage” pour simuler le code de frappe. 😉

Ma solution affiche le pourcentage de l’archive tar qui est actuellement non compressée et écrite. Je l’utilise pour écrire des images de système de fichiers racine de 2 Go. Vous avez vraiment besoin d’une barre de progression pour ces choses. Ce que je fais est d’utiliser gzip --list pour obtenir la taille totale non compressée de l’archive. À partir de cela, je calcule le facteur de blocage nécessaire pour diviser le fichier en 100 parties. Enfin, j’imprime un message de sharepoint contrôle pour chaque bloc. Pour un fichier de 2 Go, cela donne environ 10 Mo de bloc. Si c’est trop gros, vous pouvez diviser le BLOCKING_FACTOR de 10 ou 100, mais il est plus difficile d’imprimer un joli résultat en pourcentage.

En supposant que vous utilisez Bash, vous pouvez utiliser la fonction shell suivante

 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} } 

Tout d’abord, la barre n’est pas le seul indicateur de progression de la conduite. L’autre (peut-être même plus connu) est pv (visualiseur de pipe).

Deuxièmement, bar et pv peuvent être utilisés par exemple comme ceci:

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

ou même:

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

Une astuce utile si vous voulez utiliser bar et pv dans des commandes qui travaillent avec des fichiers donnés dans des arguments, comme par exemple copy file1 file2, consiste à utiliser la substitution de processus :

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

La substitution de processus est une chose magique qui crée des fichiers fifo temporaires / dev / fd / et connecte stdout à partir d'un processus exécuté (entre parenthèses) via ce tube et copy le voit comme un fichier ordinaire (à une exception près: vers l'avant).

Mettre à jour:

La commande de barre elle-même permet également de copier. Après man bar:

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

Mais la substitution de processus est à mon avis un moyen plus générique de le faire. Un il utilise le programme cp lui-même.

La plupart des commandes Unix ne vous donneront pas le type de retour direct à partir duquel vous pouvez le faire. Certains vous donneront des résultats sur stdout ou stderr que vous pouvez utiliser.

Pour quelque chose comme tar, vous pouvez utiliser le commutateur -v et diriger la sortie vers un programme qui met à jour une petite animation pour chaque ligne lue. Comme tar écrit une liste de fichiers, le programme peut mettre à jour l’animation. Pour compléter un pourcentage, vous devez connaître le nombre de fichiers et compter les lignes.

cp ne donne pas ce genre de sortie à ma connaissance. Pour surveiller la progression de cp, vous devez surveiller les fichiers source et de destination et surveiller la taille de la destination. Vous pouvez écrire un petit programme c en utilisant l’appel système stat (2) pour obtenir la taille du fichier. Cela permet de lire la taille de la source, puis d’interroger le fichier de destination et de mettre à jour une barre de pourcentage complet en fonction de la taille du fichier écrit à ce jour.

Je préfère utiliser le dialog avec le paramètre –gauge . Est utilisé très souvent dans les installations de paquets .deb et autres éléments de configuration de base de nombreuses dissortingbutions. Donc, vous n’avez pas besoin de réinventer la roue … encore une fois

Il suffit de mettre une valeur int de 1 à 100 @stdin. Un exemple basique et idiot:

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

J’ai ce fichier / bin / Wait (avec chmod u + x perms) à des fins de cuisson: 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" 

Donc je peux mettre:

Wait "34 min" "warm up the oven"

ou

Wait "dec 31" "happy new year"

pour moi le plus facile à utiliser et le plus beau à ce jour est la commande pv ou bar comme un gars a déjà écrit

par exemple: besoin de faire une sauvegarde du lecteur entier avec dd

normalement vous utilisez dd if="$input_drive_path" of="$output_file_path"

avec pv vous pouvez le faire comme ceci:

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

et le progrès va directement à STDOUT comme ceci:

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

après il est fait résumé revient

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

Pour indiquer la progression de l’activité, essayez les commandes suivantes:

 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; 

OU

 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; 

OU

 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; 

OU

 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; 

On peut utiliser des drapeaux / variables dans la boucle while pour vérifier et afficher la valeur / l’étendue de la progression.

Beaucoup de réponses décrivent l’écriture de vos propres commandes pour imprimer '\r' + $some_sort_of_progress_msg . Le problème est parfois que l’impression de centaines de ces mises à jour par seconde ralentit le processus.

Cependant, si l’un de vos processus produit une sortie (par exemple, 7z a -r newZipFile myFolder affichera chaque nom de fichier au fur et à mesure qu’il le compresse), une solution plus simple, rapide, indolore et personnalisable existe.

Installez le module 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 

Aide: tqdm -h . Un exemple utilisant plus d’options:

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

En bonus, vous pouvez également utiliser tqdm pour emballer les itérables en code python.

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

Sur la base du travail d’Edouard Lopez, j’ai créé une barre de progression qui correspond à la taille de l’écran, quelle qu’elle soit. Vérifiez-le.

entrer la description de l'image ici

Il est également affiché sur 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 

Prendre plaisir

En utilisant les suggestions listées ci-dessus, j’ai décidé de mettre en place ma propre barre de progression.

 #!/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 "$@" 

Ceci n’est applicable qu’en utilisant gnome zenity. Zenity fournit une excellente interface native aux scripts bash: https://help.gnome.org/users/zenity/stable/

Exemple de barre de progression 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 

J’ai utilisé une réponse de Créer une chaîne de caractères répétés dans un script shell pour la répétition de caractères. J’ai deux versions bash relativement petites pour les scripts qui doivent afficher une barre de progression (par exemple, une boucle qui parcourt de nombreux fichiers, mais qui n’est pas utile pour les gros fichiers tar ou les opérations de copie). Le plus rapide consiste en deux fonctions, l’une pour préparer les chaînes pour l’affichage des barres:

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

et un pour afficher une barre de progression:

 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 } 

Il pourrait être utilisé comme:

 preparebar 50 "#" 

ce qui signifie préparer des chaînes pour la barre avec 50 caractères “#”, et après cela:

 progressbar 35 80 

affichera le nombre de caractères “#” correspondant au rapport 35/80:

 [##################### ] 

Sachez que cette fonction affiche la barre sur la même ligne jusqu’à ce que vous (ou un autre programme) imprime une nouvelle ligne. Si vous mettez -1 comme premier paramètre, la barre sera effacée:

 progressbar -1 80 

La version plus lente est tout en une fonction:

 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 } 

et il peut être utilisé comme (le même exemple que ci-dessus):

 progressbar 35 80 50 

Si vous avez besoin de la barre de progression sur stderr, ajoutez simplement >&2 à la fin de chaque commande printf.

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

pourrait créer une fonction qui dessine ceci sur une échelle, par exemple 1-10 pour le nombre de barres:

 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 

J’ai fait une version shell pure pour un système embarqué profitant de:

  • Fonction de traitement du signal SIGUSR1 de / usr / bin / dd.

    Fondamentalement, si vous envoyez un “kill SIGUSR1 $ (pid_of_running_dd_process)”, cela affichera un résumé de la vitesse de transfert et de la quantité transférée.

  • arrière-plan dd, puis l’interroger régulièrement pour les mises à jour et générer des ticks de hachage comme les anciens clients ftp habitués.

  • Utiliser / dev / stdout comme destination pour les programmes non stdout comme scp

Le résultat final vous permet de prendre n’importe quelle opération de transfert de fichier et d’obtenir une mise à jour de la progression qui ressemble à la sortie de hachage FTP de la vieille école où vous obtiendrez simplement une marque de hachage pour chaque X octet.

Ceci est à peine le code de qualité de production, mais vous avez l’idée. Je pense que c’est mignon.

Pour ce que cela vaut, le nombre d’octets réel peut ne pas être reflété correctement dans le nombre de hachages – vous pouvez en avoir un plus ou moins en fonction des problèmes d’arrondi. Ne l’utilisez pas dans le cadre d’un script de test, c’est juste un vrai plaisir. Et, oui, je suis conscient que c’est terriblement inefficace – c’est un script shell et je ne m’en excuse pas.

Exemples avec wget, scp et tftp fournis à la fin. Il devrait fonctionner avec tout ce qui émet des données. Veillez à utiliser / dev / stdout pour les programmes qui ne sont pas compatibles avec stdout.

 #!/bin/sh # # Copyright (C) Nathan Ramella (nar+progress-script@remix.net) 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 sortingck _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 ssortingng. 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 } 

Exemples:

 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 user@192.168.1.1:~/myfile.tar /dev/stdout | progress_filter 

Dans le cas où vous devez afficher une barre de progression temporelle (en connaissant à l’avance l’heure affichée), vous pouvez utiliser Python comme suit:

 #!/bin/python from time import sleep import sys if len(sys.argv) != 3: print "Usage:", sys.argv[0], "", "" 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 "" 

Ensuite, en supposant que vous avez enregistré le script Python en tant que progressbar.py , il est possible d’afficher la barre de progression à partir de votre script bash en exécutant la commande suivante:

 python progressbar.py 10 50 

Il afficherait une barre de progression de 50 caractères et “en cours d’exécution” pendant 10 secondes.

J’ai construit sur la réponse fournie par d’extrême peur

Cela se connecte à une firebase database Oracle pour récupérer la progression d’une restauration 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 ssortingng lengths _fill=$(printf "%${_done}s") _empty=$(printf "%${_left}s") # 1.2 Build progressbar ssortingngs 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 <  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' 

Ceci est une barre de progression psychédélique pour les scripts bash de nExace. Il peut être appelé à partir de la ligne de commande sous la forme «./progressbar xy», où «x» correspond à une heure en secondes et «y» est un message associé à cette partie de la progression.

La fonction interne progressbar () est également très utile si vous souhaitez que d’autres parties de votre script contrôlent la barre de progression. Par exemple, l’envoi de la barre de progression 10 “Création de l’arborescence de répertoires”; ‘ Affichera:

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

Bien sûr, ce sera bien psychédélique si …

 #!/bin/bash if [ "$#" -eq 0 ]; then echo "x is \"time in seconds\" and z is \"message\""; echo "Usage: progressbar xz"; 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 

Commencez par exécuter le processus en arrière-plan, puis surveillez fréquemment son état d’exécution, exécutez l’impression du modèle et vérifiez à nouveau que le statut était en cours d’exécution ou non.

Utilisation de la boucle while pour regarder fréquemment l’état du processus.

utilisez pgrep ou toute autre commande pour regarder et obtenir le statut d’exécution d’un processus.

if using pgrep redirect the unnecessary output to /dev/null as needed.

Code:

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

This “#” will printed until sleep terminate,this method used to implement the progress bar for progress time of program.

you can also use this method to the commands to shell scripts for analyze it process time as visual.

BUG: this pgrep method doesn’t works in all situations,unexpectedly the another process was running with same name, the while loop does not end.

so getting the process running status by specify it’s PID, using may the process can available with some commands,

the command ps a will list all the process with id,you need grep to find-out the pid of the specified process

I wanted to track progress based on the number of lines a command output against a target number of lines from a previous run:

 #!/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 $? } 

Ensuite, utilisez-le comme ceci:

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

It outputs a progress bar that looks something like this:

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

The bar grows as the number of lines output reaches the target. If the number of lines exceeds the target, the bar starts over (hopefully the target is good).

BTW: I’m using bash on Mac OSX. I based this code on a spinner from mariascio .

To make a tar progress bar

 tar xzvf pippo.tgz |xargs -L 19 |xargs -I@ echo -n "." 

Where “19” is the number of files in the tar divided the length of the intended progress bar. Example: the .tgz contains 140 files and you’ll want a progress bar of 76 “.”, you can put -L 2.

You’ll need nothing else.