2010-03-11 6 views
1

En plus de ma requête précédente concernant le multi-threading dans le script shell Je suis curieux de savoir s'il est possible d'avoir plusieurs barres de progression.Barre de progression multiple

Voici un extrait de code de mon résultat attendu:

Output : 1 of 100 Files Completed # Thread1 
Output : 10 of 45 files Completed  # Thread 2  

Les lignes sont mises à jour montrant les progrès. Serait-il possible de l'implémenter? Apprécierait votre aide si quelqu'un a une idée à ce sujet.

Cordialement Kiran

Répondre

1

Comme quoi pv -c fait?

Bien sûr, voir src/pv/cursor.c. Bien que ce ne soit pas vraiment faisable en toute sécurité à partir de la coque, un petit utilitaire C pourrait en prendre soin.

+0

est-il possible avec printf instructions dans shell avec différents caractères d'échappement \ n \ r etc ?? – Kiran

+0

Pas vraiment. Comment empêchez-vous les deux threads d'écrire au terminal en même temps et de déconner les lignes? Et vous devez utiliser les échappements ANSI pour définir la position du curseur * en haut * d'une ligne. – ephemient

+0

Ya éphémère, c'est ce que je regarde. Si c'est possible en utilisant le script shell seul .. Je sais, je m'attends trop .. Serait bien si je pouvais le faire .. – Kiran

1

Oui, c'est très possible.

En supposant que votre code existant (en fonction de vos messages précédents) va actuellement quelque chose comme ceci:

do_something() { 
    ... 
    echo -ne "\r$index of $No_of_Files Completed" 
    ... 
} 

do_something A & 
do_something B & 
do_something C & 
wait 

... vous pouvez alors effectuer les réglages suivants afin d'obtenir l'effet que vous aviez en tête :

# Background tasks will no longer write directly to the console; instead, 
# they will write to temporary files which will be read periodically 
# by a special log printer task (which will display everything nicely.) 
# 
# Name of temporary files 
STATUS_BASENAME="/tmp/~$$.status" 
# Process IDs of backgrounded tasks; we record them so we can wait on them 
# specifically but not wait on the special log printer task 
TASK_PIDS="" 

do_something() { 
    # First parameter must be a task ID starting at 0 incremented by 1 
    TASK_ID=$1 ; shift 
    ... 
    # We write new status to status file (note we don't echo -n, we want that 
    # trailing newline) 
    # Try to go through a temporary status file which we rename afterwards to 
    # avoid race conditions with the special log printer task 
    echo "$x of 5 Completed" >"${STATUS_BASENAME}.${TASK_ID}.tmp" 
    mv "${STATUS_BASENAME}.${TASK_ID}.tmp" "${STATUS_BASENAME}.${TASK_ID}" 
    ... 
} 

# Special log printer task 
status_printer() { 
    # First time in the loop is special insofar we don't have to 
    # scroll up to overwrite previous output. 
    FIRST_TIME=1 
    while true ; do 
    # If not first time, scroll up as many lines as we have 
    # regular background tasks to overwrite previous output. 
    test $FIRST_TIME -eq 0 && for PID in $TASK_PIDS ; do 
     echo -ne '\033M' # scrol up one line using ANSI/VT100 cursor control sequences 
    done 
    FIRST_TIME=0 
    TASK_ID=0 
    for PID in $TASK_PIDS ; do 
     # If status file exists print first line 
     test -f "${STATUS_BASENAME}.${TASK_ID}" && head -1 "${STATUS_BASENAME}.${TASK_ID}" || echo "waiting..." 
     TASK_ID=`expr $TASK_ID + 1` # using expr for portability :) 
    done 
    test -f "${STATUS_BASENAME}.done" && return 
    sleep 1 # seconds to wait between updates 
    done 
} 

do_something 0 A & 
TASK_PIDS="$TASK_PIDS $!" 
do_something 1 B & 
TASK_PIDS="$TASK_PIDS $!" 
do_something 2 C & 
TASK_PIDS="$TASK_PIDS $!" 

status_printer & 
    PRINTER_PID=$! 

# Wait for background tasks 
wait $TASK_PIDS 

# Stop special printer task instead of doing just 
# kill $PRINTER_PID >/dev/null 
touch "${STATUS_BASENAME}.done" 
wait $PRINTER_PID 

# Cleanup 
rm -f "${STATUS_BASENAME}."* 
+0

Merci beaucoup de prendre votre temps dans le développement de ce code .. Je vais essayer si cela correspond à mon cadre. Je pensais s'il y avait une façon évidente d'utiliser une combinaison de déclarations echo et printf. Appréciez toute votre aide – Kiran

0

Si votre sortie subprocess est filtrables alors vous pouvez rediriger stdout de chaque subproc à un descripteur de fichier différent, puis appeler une fonction à boucle à travers la sortie de ce descripteur de fichier. Ensuite, vous pouvez essayer d'utiliser printf pour mettre à jour l'indicateur de progression. C'est là que vous rencontrerez des problèmes cependant. Je ne suis pas certain que le printf intégré de Bash puisse gérer le terminal selon ce détail. Je n'ai jamais essayé d'écrire un compteur de progression dans Bash qui produit une sortie multi-ligne. Pourquoi ne pas utiliser le dialogue?