A puzzle with a printing function executing in background

Somebody on a thread in the (french) Mandriva Forum recently suggested a script, designed to provide a tool to display kind of "temporisation widgets" on the console (to be ultimately pasted in other more complex scripts).
One version of this script was something like the following, which seems to work fine (it displays a spinning cross and it end with just ONE ENTER keystroke) :

(sorry for not having translated comments from french)

    #!/bin/bash

    # Arr�t par cr�ation de fichier
    # Version:1.0.2c
    # Au choix: croix tournante ou barre d'avancement;
    # inverser les commentaires pour s�lectionner la boucle du
    # mode choisi. Pour arr�ter et revenir � l'invite : taper ENTREE.
    #
    #
    clear;echo

    #+++++++++++++++++++++++++++++++++++++++
    # partie � ins�rer dans un script (supprimer la boucle superflue)

      PID=$$ # PID du processus p�re

        trap "rm -f $STOP; exit"  HUP  INT  QUIT  ABRT  TERM

    # Affiche la barre d'avancement (ici 5 motifs/s)
      function barre()
      {
        tput civis;tput bold;tput sc;x=0
        
        # Displays 5 sharps/seconds
       #--------------------------
       # COLS=$(tput cols) # M�morise la largeur du terminal
       # while : ; do
       #    sleep 0.2
       #    tput rc;tput hpa $x;tput el
       #    echo -n "#"
       #    let "x += 1"
       #    if [ $x = $COLS ]; then tput rc;tput dl1;x=0;fi
       #    if [ -f "$STOP" ]; then break;fi
       #    if [ $((x % 5)) = 0 ]; then # si Ctrl-c a tu� le p�re, arr�te le fils
       #        if [ "$(ps h $PID)" = "" ]; then break;fi
       #    fi
       # done
        #--------------------------

        # Displays spinning cross
        #---------------------------------------
           while : ; do
               sleep 0.125;tput rc;tput dl1;echo -n "      |"
               sleep 0.125;tput rc;tput dl1;echo -n "      /"
               sleep 0.125;tput rc;tput dl1;echo -n "      -"
               sleep 0.125;tput rc;tput dl1;echo -n "      \\"
               sleep 0.125;tput rc;tput dl1;echo -n "      |"
               sleep 0.125;tput rc;tput dl1;echo -n "      /"
               sleep 0.125;tput rc;tput dl1;echo -n "      -"
               sleep 0.125;tput rc;tput dl1;echo -n "      \\"
               if [ -f $STOP ]; then break;fi
               if [ "$(ps h $PID)" = "" ]; then break;fi
            done
            #---------------------------------------
        
        rm -f $STOP
        tput rc;tput dl1;tput sgr0;tput cnorm;tput ed
      }

    #++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    # fin de la fonction pour un script

    # Lancement de la fonction barre
      barre &
    # Instructions d'arr�t de la fonction
      read
      STOP=$(mktemp  --suffix=.stop-barre --tmpdir=$HOME/tmp)
      tput rc;tput dl1
      sleep 1       # faire une pause pour revenir en avant-plan
                     # avant d'envoyer une commande d'avant plan.
      exit 0

The problem is now for another version of this script, which is exactly the same with just some commented and uncommented lines, and which displays a line of sharps (#) (five # / second).

It works but - for some reason - it ends and returns to shell invite with TWO ENTER keystrokes.

    #!/bin/bash

    # Arr�t par cr�ation de fichier
    # Version:1.0.2c
    # Au choix: croix tournante ou barre d'avancement;
    # inverser les commentaires pour s�lectionner la boucle du
    # mode choisi. Pour arr�ter et revenir � l'invite : taper ENTREE.
    #
    #
    clear;echo

    #+++++++++++++++++++++++++++++++++++++++
    # partie � ins�rer dans un script (supprimer la boucle superflue)

      PID=$$ # PID du processus p�re

        trap "rm -f $STOP; exit"  HUP  INT  QUIT  ABRT  TERM

    # Displays a bar (with sharps) or a cross
      function barre()
      {
        tput civis;tput bold;tput sc;x=0

        #--------------------------
        COLS=$(tput cols)    # M�morise la largeur du terminal
        while : ; do
           sleep 0.2
           tput rc;tput hpa $x;tput el
           echo -n "#"
           let "x += 1"
           if [ $x = $COLS ]; then tput rc;tput dl1;x=0;fi
           if [ -f "$STOP" ]; then break;fi
           if [ $((x % 5)) = 0 ]; then # si Ctrl-c a tu� le p�re, arr�te le fils
               if [ "$(ps h $PID)" = "" ]; then break;fi
           fi
        done
        #--------------------------

        # Displays spinning cross
        #---------------------------------------
        #   while : ; do
        #      sleep 0.125;tput rc;tput dl1;echo -n "      |"
        #      sleep 0.125;tput rc;tput dl1;echo -n "      /"
        #      sleep 0.125;tput rc;tput dl1;echo -n "      -"
        #      sleep 0.125;tput rc;tput dl1;echo -n "      \\"
        #      sleep 0.125;tput rc;tput dl1;echo -n "      |"
        #      sleep 0.125;tput rc;tput dl1;echo -n "      /"
        #      sleep 0.125;tput rc;tput dl1;echo -n "      -"
        #      sleep 0.125;tput rc;tput dl1;echo -n "      \\"
        #      if [ -f $STOP ]; then break;fi
        #      if [ "$(ps h $PID)" = "" ]; then break;fi
        #   done
            #---------------------------------------
        
        rm -f $STOP
        tput rc;tput dl1;tput sgr0;tput cnorm;tput ed
      }

    #++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    # fin de la fonction pour un script

    # Lancement de la fonction barre
      barre &
    # Instructions d'arr�t de la fonction
      read
      STOP=$(mktemp  --suffix=.stop-barre --tmpdir=$HOME/tmp)
      tput rc;tput dl1
      sleep 1       # faire une pause pour revenir en avant-plan
                     # avant d'envoyer une commande d'avant plan.
      exit 0

Why such different behaviours ? And how to get the second version to end and go back to the shell prompt with just ONE (ENTER) keystroke.

---------- Post updated at 08:34 PM ---------- Previous update was at 08:28 PM ----------

For the french-speaking of you see the discussion about some aspects of this script :

http://forum.mandriva.com/fr/viewtopic.php?p=840962#p840962

IMO is is because the variable STOP is not set, so in the first script the following is evaluated:

[ -f ] 

and in the second script

[ -f "" ]

So the first script does not use double quotes and the second does.

This produces different outcomes:

$ [ -f ] && echo hello
hello
$ [ -f "" ] && echo hello
$

I shall try it. Thanks.

---------- Post updated at 09:48 AM ---------- Previous update was at 07:50 AM ----------

It seems that I was mistaken. In the versions given above it seems (?) that the value of the variable STOP cannot be made available to the function barre() running in background, at least if the variable is created at the point of the script where I created it.
For other (working) versions, see the link I gave above.

Nonethelesss I seems to me that is what accounted for the difference in the number of enters needed. If I put the assignment to STOP in the proper place before the calling of "barre" then both scripts need two keystrokes to finish....

Yes. You are right.

---------- Post updated at 02:16 PM ---------- Previous update was at 11:36 AM ----------

Here is both versions going back to prompt with just ONE (ENTER) keystroke :

The one which displays a bar of sharps :

    
    #!/bin/bash -
    # Arr�t par cr�ation de fichier
    # Version:1.0.2d
    # Au choix: croix tournante ou barre d'avancement; 
    # Inverser les commentaires pour s�lectionner la boucle du
    # mode choisi. Faire Entr�e pour arr�ter le processus.
    #

    clear;echo

    #+++++++++++++++++++++++++++++++++++++++ partie � ins�rer en t�te de script (supprimer la boucle superflue)

    PID=$$

    # initialisation
    barre-init()
    {
      STOP=$(mktemp -u --suffix=.stop-barre  --tmpdir=$HOME/tmp)
      trap "rm -f $STOP; exit" EXIT HUP  INT  QUIT  ABRT  TERM
    }

    # Affiche une barre avec des di�ses ou une croix tournante
    function barre()
    {
       tput civis;tput bold;tput sc
    
      # Affiche une barre avec des di�ses (5 '#'/s)
      #--------------------------
      COLS=$(tput cols);x=0   # M�morise la largeur du terminal
         while : ; do
           sleep 0.2;tput rc;tput hpa $x;tput el;echo -n "#"
           let "x += 1"
           if [ $x = $COLS ]; then tput rc;tput dl1;x=0;fi
           if [ -f $STOP ]; then break;fi
           if [ $((x % 5)) = 0 ]; then
              if [ "`ps h $PID`" = "" ]; then break;fi
           fi
         done
      #--------------------------

      # Affiche la croix tournante (1 rotation/s)
      #---------------------------------------
      #   while : ; do
      #     sleep 0.125;tput rc;tput dl1;echo -n "      |"
      #     sleep 0.125;tput rc;tput dl1;echo -n "      /"
      #     sleep 0.125;tput rc;tput dl1;echo -n "      -"
      #     sleep 0.125;tput rc;tput dl1;echo -n "      \\"
      #     sleep 0.125;tput rc;tput dl1;echo -n "      |"
      #     sleep 0.125;tput rc;tput dl1;echo -n "      /"
      #     sleep 0.125;tput rc;tput dl1;echo -n "      -"
      #     sleep 0.125;tput rc;tput dl1;echo -n "      \\"
      #     if [ -f $STOP ]; then break;fi
      #     if [ "`ps h $PID`" = "" ]; then break;fi
      #   done
      #---------------------------------------

      tput rc;tput dl1;tput sgr0;tput cnorm;tput ed
    }

    #++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fin de la fonction pour un script

    # Lancement de la fonction: barre
    barre-init  #  � placer dans un script au  d�but de l'op�ration: t�l�chargement, recherche etc... ***
    barre &    # idem ***

    # Instructions d'arr�t de ce script
    read
    > $STOP  # instruction d'arr�t de la barre d'attente � placer � la fin de l'op�ration ***
    tput rc;tput dl1
    sleep 1      # faire une pause pour revenir en avant plan avant d'envoyer une commande d'avant plan.

    exit 0

and the one which displays a rotating cross :

    
    #!/bin/bash -
    # Arr�t par cr�ation de fichier
    # Version:1.0.2d
    # Au choix: croix tournante ou barre d'avancement; 
    # Inverser les commentaires pour s�lectionner la boucle du
    # mode choisi. Faire Entr�e pour arr�ter le processus.
    #

    clear;echo

    #+++++++++++++++++++++++++++++++++++++++ partie � ins�rer en t�te de script (supprimer la boucle superflue)

    PID=$$

    # initialisation
    barre-init()
    {
      STOP=$(mktemp -u --suffix=.stop-barre  --tmpdir=$HOME/tmp)
      trap "rm -f $STOP; exit" EXIT HUP  INT  QUIT  ABRT  TERM
    }

    # Affiche une barre avec des di�ses ou une croix tournante
    function barre()
    {
       tput civis;tput bold;tput sc
    
      # Affiche une barre avec des di�ses (5 '#'/s)
      #--------------------------
      # COLS=$(tput cols);x=0   # M�morise la largeur du terminal
      #   while : ; do
      #     sleep 0.2;tput rc;tput hpa $x;tput el;echo -n "#"
      #     let "x += 1"
      #     if [ $x = $COLS ]; then tput rc;tput dl1;x=0;fi
      #     if [ -f $STOP ]; then break;fi
      #     if [ $((x % 5)) = 0 ]; then
      #        if [ "`ps h $PID`" = "" ]; then break;fi
      #     fi
      #   done
      #--------------------------

      # Affiche la croix tournante (1 rotation/s)
      #---------------------------------------
         while : ; do
           sleep 0.125;tput rc;tput dl1;echo -n "      |"
           sleep 0.125;tput rc;tput dl1;echo -n "      /"
           sleep 0.125;tput rc;tput dl1;echo -n "      -"
           sleep 0.125;tput rc;tput dl1;echo -n "      \\"
           sleep 0.125;tput rc;tput dl1;echo -n "      |"
           sleep 0.125;tput rc;tput dl1;echo -n "      /"
           sleep 0.125;tput rc;tput dl1;echo -n "      -"
           sleep 0.125;tput rc;tput dl1;echo -n "      \\"
           if [ -f $STOP ]; then break;fi
           if [ "`ps h $PID`" = "" ]; then break;fi
         done
      #---------------------------------------

      tput rc;tput dl1;tput sgr0;tput cnorm;tput ed
    }

    #++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fin de la fonction pour un script

    # Lancement de la fonction: barre
    barre-init  #  � placer dans un script au  d�but de l'op�ration: t�l�chargement, recherche etc... ***
    barre &    # idem ***

    # Instructions d'arr�t de ce script
    read
    > $STOP  # instruction d'arr�t de la barre d'attente � placer � la fin de l'op�ration ***
    tput rc;tput dl1
    sleep 1      # faire une pause pour revenir en avant plan avant d'envoyer une commande d'avant plan.

    exit 0

Just a few of improvements.

It's much more efficient to run tput and store it's output in a variable rather than re-running it each time you need an escape character.
Why not loop thru the 4 chars in a for loop
If you have /proc it's much more efficient to test from /proc/$PID directory rather than running ps:

so replace

while : ; do
    sleep 0.125;tput rc;tput dl1;echo -n "      |"
    sleep 0.125;tput rc;tput dl1;echo -n "      /"
    sleep 0.125;tput rc;tput dl1;echo -n "      -"
    sleep 0.125;tput rc;tput dl1;echo -n "      \\"
    sleep 0.125;tput rc;tput dl1;echo -n "      |"
    sleep 0.125;tput rc;tput dl1;echo -n "      /"
    sleep 0.125;tput rc;tput dl1;echo -n "      -"
    sleep 0.125;tput rc;tput dl1;echo -n "      \\"
    if [ -f $STOP ]; then break;fi
    if [ "`ps h $PID`" = "" ]; then break;fi
done

with

BACK=$(tput rc;tput dl1)
while : ; do
    for char in \| / - \\ ; do
        sleep 0.125;echo -n "$BACK      $char"
    done
    [ -f $STOP ] && break
    [ -d /proc/$PID ] || break
done

Nice indeed !
Thanks.

---------- Post updated at 06:44 PM ---------- Previous update was at 04:19 PM ----------

The sharp version was modified, it looks now like this :

    PID=$$    

    BARREGRAPH()
    {   case $1 in
         "start") 
                  STOP=$(mktemp -u --tmpdir=$HOME/tmp)
                  ( trap "rm -f $STOP; exit" EXIT HUP  INT  QUIT  ABRT  TERM
                    tput civis;tput sc;COLS=$(tput cols);x=0
                    until [ -f $STOP  -o  ! -d /proc/$PID  ] ; do
                       sleep 0.2
                       tput rc
                       tput hpa $x
                       tput el
                       echo -n "#"
                       let "x += 1"
                       if [ $x = $COLS ]; then 
                                tput rc
                                tput dl1
                                x=0
                       fi
                    done
                      tput rc
                      tput dl1
                      tput cnorm
                   ) &;;
         "stop") 
                   [ "$STOP" = "" ] || > $STOP;;
        esac
    }

    BARREGRAPH start
    read
    BARREGRAPH stop
    sleep 1