33.5. "Colorare" con gli script

Le sequenze di escape ANSI [1] impostano gli attributi dello schermo, come il testo in grassetto e i colori del primo piano e dello sfondo. I file batch DOS usano comunemente i codici di escape ANSI per colorare i loro output, e altrettanto possono fare gli script Bash.

Esempio 33-11. Una rubrica di indirizzi "a colori"

#!/bin/bash
# ex30a.sh: Versione di ex30.sh "a colori".
#           Un database di indirizzi non molto elegante


clear                                   # Pulisce lo schermo.

echo -n "          "
echo -e '\E[37;44m'"\033[1mElenco Contatti\033[0m"
                                        # Bianco su sfondo blu
echo; echo
echo -e "\033[1mScegliete una delle persone seguenti:\033[0m"
                                        # Grassetto
tput sgr0
echo "(Inserite solo la prima lettera del nome.)"
echo
echo -en '\E[47;34m'"\033[1mE\033[0m"   # Blu
tput sgr0                               # Ripristina i colori "normali."
echo "vans, Roland"                     # "[E]vans, Roland"
echo -en '\E[47;35m'"\033[1mJ\033[0m"   # Magenta
tput sgr0
echo "ones, Mildred"
echo -en '\E[47;32m'"\033[1mS\033[0m"   # Verde
tput sgr0
echo "mith, Julie"
echo -en '\E[47;31m'"\033[1mZ\033[0m"   # Rosso
tput sgr0
echo "ane, Morris"
echo

read persona

case "$persona" in
# Notate l'uso del "quoting" per la variabile.

  "E" | "e" )
  # Accetta sia una lettera maiuscola che una minuscola.
  echo
  echo "Roland Evans"
  echo "4321 Floppy Dr."
  echo "Hardscrabble, CO 80753"
  echo "(303) 734-9874"
  echo "(303) 734-9892 fax"
  echo "revans@zzy.net"
  echo "Socio d'affari & vecchio amico"
  ;;

  "J" | "j" )
  echo
  echo "Mildred Jones"
  echo "249 E. 7th St., Apt. 19"
  echo "New York, NY 10009"
  echo "(212) 533-2814"
  echo "(212) 533-9972 fax"
  echo "milliej@loisaida.com"
  echo "Fidanzata"
  echo "Compleanno: Feb. 11"
  ;;

# Aggiungete in seguito le informazioni per Smith & Zane.

          * )
   # Opzione preefinita.
   # Anche un input vuoto (è stato premuto il tasto INVIO) viene verificato qui.
   echo
   echo "Non ancora inserito nel database."
  ;;

esac

tput sgr0                               # Ripristina i colori "normali."

echo

exit 0

Esempio 33-12. Disegnare un rettangolo

#!/bin/bash
# Draw-box.sh: Disegnare un rettangolo con caratteri ASCII.

# Script di Stefano Palmeri, con modifiche secondarie dell'autore del libro
# ed altre suggerite da Jim Angstadt.
# Usato in "Guida ABS" con il consenso dell'autore dello script.


######################################################################
###  spiegazione della funzione disegna_rettangolo  ###

#  La funzione "disegna_rettangolo" permette all'utente
#+ di disegnare un rettangolo in un terminale.
#
#  Utilizzo: disegna_rettangolo RIGA COLONNA ALTEZZA BASE [COLORE]
#  RIGA e COLONNA rappresentano la posizione
#+ dell'angolo superiore sinistro del rettangolo da disegnare.
#  RIGA e COLONNA devono essre maggiori di 0
#+ e minori della dimensione del terminale corrente.
#  ALTEZZA è il numero di righe del rettangolo, e deve essere > 0.
#  ALTEZZA + RIGA deve essere <= dell'altezza del terminale corrente.
#  BASE è il numero di colonne del rettangolo e deve essere > 0.
#  BASE + COLONNA deve essere <= dell'ampiezza del terminale corrente.
#
# Es.: se la dimensione del terminale fosse di 20x80,
#  disegna_rettangolo 2 3 10 45 andrebbe bene
#  disegna_rettangolo 2 3 19 45 valore di ALTEZZA errato (19+2 > 20)
#  disegna_rettangolo 2 3 18 78 valore di BASE errato (78+3 > 80)
#
#  COLORE è il colore dei lati del rettangolo.
#  È il 5 argomento ed è opzionale.
#  0=nero 1=rosso 2=verde 3=marrone 4=blu 5=porpora 6=cyan 7=bianco.
#  Se alla funzione viene passato un numero di argomenti errato,
#+ lo script termina con il codice d'errore 65
#+ e nessun messaggio verrà visualizzato allo stderr.
#
#  Pulite lo schermo prima di iniziare a disegnare un rettangolo.
#  Il comando clear non è presente nella funzione.
#  Questo per consentire all'utente di disegnare più rettangoli,
#+ anche sovrapponendoli.

###  fine della spiegazione della funzione disegna_rettangolo  ###
######################################################################

disegna_rettangolo(){

#=============#
ORIZ="-"
VERT="|"
ANGOLO="+"

ARGMIN=4
E_ERRARG=65
#=============#


if [ $# -lt "$ARGMIN" ]; then                  #  Se gli argomenti sono meno
    exit $E_ERRARG                             #+ di 4, esce.
fi

# Controlla che gli argomenti siano solo dei numeri.
# Probabilmente potrebbe essere fatto meglio (esercizio per il lettore?).
if echo $@ | tr -d [:blank:] | tr -d [:digit:] | grep . &> /dev/null; then
   exit $E_ERRARG
fi

ALTEZZA_RET=`expr $3 - 1`  #  -1 correzione necessaria perché il carattere per
AMPIEZZA_RET=`expr $4 - 1` #+ gli angoli "+" fa parte sia dell'altezza che della
                           #+ larghezza.
RIGHE_T=`tput lines`       #  Si determina la dimensione del terminale corrente
COL_T=`tput cols`          #+ in numero di righe e colonne.
         
if [ $1 -lt 1 ] || [ $1 -gt $RIGHE_T ]; then   #  Inizio delle verifiche di
   exit $E_ERRARG                              #+ congruità degli argomenti.
fi
if [ $2 -lt 1 ] || [ $2 -gt $COL_T ]; then
   exit $E_ERRARG
fi
if [ `expr $1 + $ALTEZZA_RET + 1` -gt $RIGHE_T ]; then
   exit $E_BADARGS
fi
if [ `expr $2 + $AMPIEZZA_RET + 1` -gt $COL_T ]; then
   exit $E_ERRARG
fi
if [ $3 -lt 1 ] || [ $4 -lt 1 ]; then
   exit $E_ERRARG
fi                                 # Fine delle verifiche degli argomenti.

vis_car(){                         # Funzione all'interno di una funzione.
   echo -e "\E[${1};${2}H"$3
}

echo -ne "\E[3${5}m"               #  Imposta il colore del rettangolo,
                                   #+ se specificato.

# inizia il disegno del rettangolo

conto=1                                         #  Disegna le righe verticali
for (( r=$1; conto<=$ALTEZZA_RET; r++)); do     #+ con la funzione vis_car.
  vis_car $r $2 $VERT
  let conto=conto+1
done 

conto=1
c=`expr $2 + $AMPIEZZA_RET`
for (( r=$1; conto<=$ALTEZZA_RET; r++)); do
  vis_car $r $c $VERT
  let conto=conto+1
done 

conto=1                                        #  Disegna le righe orizzontali
for (( c=$2; conto<=$AMPIEZZA_RET; c++)); do   #+ con la funzione vis_car.
  vis_car $1 $c $ORIZ
  let conto=conto+1
done 

conto=1
r=`expr $1 + $ALTEZZA_RET`
for (( c=$2; conto<=$AMPIEZZA_RET; c++)); do
  vis_car $r $c $ORIZ
  let conto=conto+1
done

vis_car $1 $2 $ANGOLO                          # Inserisce gli angoli.
vis_car $1 `expr $2 + $AMPIEZZA_RET` $ANGOLO
vis_car `expr $1 + $ALTEZZA_RET` $2 $ANGOLO
vis_car `expr $1 + $ALTEZZA_RET` `expr $2 + $AMPIEZZA_RET` $ANGOLO

echo -ne "\E[0m"             #  Ripristina i colori precedenti.

RIGHE_P=`expr $RIGHE_T - 1`  #  Posiziona il prompt in fondo al terminale.

echo -e "\E[${RIGHE_P};1H"
}      


# Ora proviamo a disegnare il rettangolo.
clear                                          # Pulisce il terminale.
R=2      # Righe
C=3      # Colonne
A=10     # Altezza
L=45     # Larghezza
col=1    # Colore (rosso)
disegna_rettangolo $R $C $A $L $col            # Disegna il rettangolo.

exit 0

# Esercizio:
# ---------
# Aggiungete l'opzione per inserire del testo nel rettangolo.

La più semplice e, forse, più utile sequenza di escape ANSI è quella per l'impostazione del testo in grassetto, \033[1m ... \033[0m. \033 rappresenta un escape, "[1" abilita l'attributo del grassetto, mentre "[0" lo disabilita. "m" indica la fine di ogni termine della sequenza di escape.

bash$ echo -e "\033[1mQuesto testo è in grassetto.\033[0m"
	      

Una sequenza simile abilita l'attributo di sottolineatura (su terminali rxvt e aterm).

bash$ echo -e "\033[4mQuesto testo è sottolineato.\033[0m"
	      

Nota

L'opzione -e di echo abilita le sequenze di escape.

Altre sequenze modificano il colore del testo e/o dello sfondo.

bash$ echo -e '\E[34;47mQuesto viene visualizzato in blu.'; tput sgr0


bash$ echo -e '\E[33;44m'"Testo giallo su sfondo blu."; tput sgr0


bash$ echo -e '\E[1;33;44m'"Testo giallo in GRASSETTO" su sfondo blu.; tput sgr0
	      

Nota

Di solito è consigliabile impostare l'attributo di grassetto per il testo colorato in primo piano.

tput sgr0 ripristina il terminale alle normali impostazioni. Se viene omesso, tutti i successivi output, su quel particolare terminale, rimarranno blu.

Nota

Poiché tput sgr0, in certe circostanze, fallisce nel ripristinare le precedenti impostazioni, echo -ne \E[0m potrebbe rivelarsi una scelta migliore.

I numeri della seguente tabella valgono per un terminale rxvt. I risultati potrebbero variare su altri emulatori di terminale.

Tabella 33-1. Numeri che rappresentano i colori nelle sequenze di escape

ColorePrimo pianoSfondo
nero3040
rosso3141
verde3242
giallo3343
blu3444
magenta3545
cyan3646
bianco3747

Esempio 33-13. Visualizzare testo colorato

#!/bin/bash
# color-echo.sh: Visualizza messaggi colorati.

# Modificate lo script secondo le vostre necessità.
# Più facile che codificare i colori.

nero='\E[30;47m'
rosso='\E[31;47m'
verde='\E[32;47m'
giallo='\E[33;47m'
blu='\E[34;47m'
magenta='\E[35;47m'
cyan='\E[36;47m'
bianco='\E[37;47m'


alias Reset="tput sgr0"      #  Ripristina gli attributi di testo normali
                             #+ senza pulire lo schermo.


cecho ()                     # Colora-echo.
                             # Argomento $1 = messaggio
                             # Argomento $2 = colore
{
local msg_default="Non è stato passato nessun messaggio."
                             #  Veramente, non ci sarebbe bisogno di una 
                             #+ variabile locale.

messaggio=${1:-$msg_default} #  Imposta al messaggio predefinito se non ne
                             #+ viene fornito alcuno.
colore=${2:-$nero}           #  Il colore preimpostato è il nero, se
                             #+ non ne viene specificato un altro.

  echo -e "$colore"
  echo "$messaggio"
  Reset                      # Ripristina i valori normali.

  return
}  


# Ora lo mettiamo alla prova.
# ----------------------------------------------------
cecho "Mi sento triste..." $blu
cecho "Il magenta assomiglia molto al porpora." $magenta
cecho "Sono verde dall'invidia." $verde
cecho "Vedi rosso?" $rosso
cecho "Cyan, più familiarmente noto come acqua." $cyan
cecho "Non è stato passato nessun colore (nero di default)."
       # Omesso l'argomento $colore.
cecho "Il colore passato è \"nullo\" (nero di default)." ""
       # Argomento $colore nullo.
cecho
       # Omessi gli argomenti $messaggio e $colore.
cecho "" ""
       # Argomenti $messaggio e $colore nulli.
# ----------------------------------------------------

echo

exit 0

# Esercizi:
# ---------
# 1) Aggiungete l'attributo "grassetto" alla funzione 'cecho ()'.
# 2) Aggiungete delle opzioni per colorare gli sfondi.

Esempio 33-14. Una gara "ippica"

#!/bin/bash
# horserace.sh: semplicissima simulazione di una corsa di cavalli.
# Autore: Stefano Palmeri
# Usato con il permesso dell'autore.

######################################################################
#  Scopo dello script:
#  giocare con le sequenze di escape e i colori del terminale.
#
#  Esercizio:
#  Modificate lo script in modo che venga eseguito con minor casualità,
#+ mettete in piedi una finta sala scommesse . . .     
#  Um . . . um . . . incomincia a ricordarmi un film . . .
#
#  Lo script assegna a ciascun cavallo un handicap casuale.
#  Le poste vengono calcolate in base all'handicap del cavallo
#+ e sono espresse nello stile Europeo(?).
#  Es.: posta=3.75 significa che se puntate Eu.1 e vincete,
#+ riceverete Eu. 3.75.
# 
#  Lo script è stato provato su un SO GNU/Linux,
#+ utilizzando xterm e rxvt, e konsole.
#  Su una macchina con processore AMD da 900 MHz,
#+ la durata media della corsa è di 75 secondi.    
#  Su computer più veloci la durata della corsa potrebbe essere minore.
#  Quindi, se volete più suspense, reimpostate la variabile USLEEP_ARG.
#
#  Script di Stefano Palmeri.
######################################################################

E_NOESEC=65

# Verifica se sono installati md5sum, bc e usleep. *
if ! which bc &> /dev/null; then
   echo bc non è installato.  
   echo "Esecuzione interrotta . . . "
   exit $E_NOESEC
fi
if ! which md5sum &> /dev/null; then
   echo md5sum non è installato.  
   echo "Esecuzione interrotta . . . "
   exit $E_NOESEC
fi
if ! which usleep &> /dev/null; then
   echo usleep non è installato.  
   echo "Esecuzione interrotta . . . "
   exit $E_NOESEC
fi

#  Impostate la variabile seguente per rallentare l'esecuzione dello script.
#  Viene passata come argomento a usleep (man usleep)  
#+ e viene espressa in microsecondi (500000 = mezzo secondo).
USLEEP_ARG=0  

#  Cancellazione della directory temporanea, ripristino del cursore e 
#+ dei colori del terminale -- nel caso lo script venga interrotto con Ctl-C.
trap 'echo -en "\E[?25h"; echo -en "\E[0m"; stty echo;\
tput cup 20 0; rm -fr  $CORSA_CAVALLI_DIR_TMP'  TERM EXIT
#  Vedi il capitolo sul debugging per la spiegazione di 'trap.'

#  Impostazione di un nome univoco (paranoico) per la directory temporanea
#+ necessaria allo script.
CORSA_CAVALLI_DIR_TMP=$HOME/.corsacavalli-`date +%s`-`head -c10 /dev/urandom |\
 md5sum | head -c30`

# Crea la directory temporanea e vi accede.
mkdir $CORSA_CAVALLI_DIR_TMP
cd $CORSA_CAVALLI_DIR_TMP


#  La funzione che segue serve a spostare il cursore alla riga $1 colonna $2,
#+ e a visualizzare $3.
#  Es.: "sposta_e_visualizza 5 10 linux" equivale a
#+ "tput cup 4 9; echo linux", con un unico comando, però, invece di due.
#  Nota: "tput cup" identifica con 0 0 l'angolo superiore sinistro del 
#+ terminale, mentre echo lo identifica con 1 1.
sposta_e_visualizza() {
          echo -ne "\E[${1};${2}H""$3" 
}

# Funzione per generare un numero pseudocasuale compreso tra 1 e 9. 
casuale_1_9 () {
              head -c10 /dev/urandom | md5sum | tr -d [a-z] | tr -d 0 | cut -c1 
}

#  Due funzioni per simulare il "movimento" dei cavalli. 
disegna_cavallo_uno() {
              echo -n " "//$MUOVI_CAVALLO//
}
disegna_cavallo_due(){
              echo -n " "\\\\$MUOVI_CAVALLO\\\\ 
}   


# Determinazione delle dimensioni del terminale corrente.
N_COLONNE=`tput cols`
N_RIGHE=`tput lines`

# Il terminale deve essere di almeno 20-RIGHE X 80-COLONNE. Lo verifica.
if [ $N_COLONNE -lt 80 ] || [ $N_RIGHE -lt 20 ]; then
   echo "`basename $0` necessita di un terminale di 80-colonne X 20-righe."
   echo "Il terminale corrente è di ${N_COLONNE}-colonne X ${N_RIGHE}-righe."
   exit $E_NOESEC
fi


# Disegno del campo di gara.

# È necessaria una stringa di 80 caratteri. Vedi sopra.
STRINGA80=`seq -s "" 100 | head -c80`

clear

# Imposta a bianco i colori del primo piano e dello sfondo.
echo -ne '\E[37;47m'

# Sposta il cursore nell'angolo superiore sinistro del terminale.
tput cup 0 0 

# Traccia sei righe bianche.
for n in `seq 5`; do
      echo $STRINGA80        #  Usa una stringa di 80 caratteri per 
                             #+ colorare il terminale.  
done

# Imposta a nero il colore del primo piano. 
echo -ne '\E[30m'

sposta_e_visualizza 3 1 "START  1"            
sposta_e_visualizza 3 75 FINISH
sposta_e_visualizza 1 5 "|"
sposta_e_visualizza 1 80 "|"
sposta_e_visualizza 2 5 "|"
sposta_e_visualizza 2 80 "|"
sposta_e_visualizza 4 5 "|  2"
sposta_e_visualizza 4 80 "|"
sposta_e_visualizza 5 5 "V  3"
sposta_e_visualizza 5 80 "V"

# Imposta a rosso il colore del primo piano. 
echo -ne '\E[31m'

# Un po' di ASCII art.
sposta_e_visualizza 1 8 "..@@@..@.....@.....@@@@....."
sposta_e_visualizza 2 8 ".@...@.@.....@....@........."
sposta_e_visualizza 3 8 ".@@@@@.@.....@....@@@@......"
sposta_e_visualizza 4 8 ".@...@.@.....@....@........."
sposta_e_visualizza 5 8 ".@...@.@@@@..@@@@..@@@@....."
sposta_e_visualizza 1 37 ".@@@@..@@@..@@@@...@@@@..@@@@..."
sposta_e_visualizza 2 37 "@.....@...@.@...@.@.....@......."
sposta_e_visualizza 3 37 "@.....@...@.@@@@...@@@..@@@@...."
sposta_e_visualizza 4 37 "@.....@...@.@..@......@.@......."
sposta_e_visualizza 5 37 ".@@@@..@@@..@...@.@@@@...@@@@..."


# Imposta a verde i colori del primo piano e dello sfondo.
echo -ne '\E[32;42m'

# Traccia undici righe verdi.
tput cup 5 0
for n in `seq 11`; do
      echo $STRINGA80
done

# Imposta a nero il colore del primo piano. 
echo -ne '\E[30m'
tput cup 5 0

# Traccia i bordi pista. 
echo "++++++++++++++++++++++++++++++++++++++\
++++++++++++++++++++++++++++++++++++++++++"

tput cup 15 0
echo "++++++++++++++++++++++++++++++++++++++\
++++++++++++++++++++++++++++++++++++++++++"

# Imposta a bianco i colori del primo piano e dello sfondo.
echo -ne '\E[37;47m'

# Traccia tre righe bianche.
for n in `seq 3`; do
      echo $STRINGA80
done

# Imposta a nero il colore del primo piano.
echo -ne '\E[30m'

# Crea 9 file in cui registrare gli handicap.
for n in `seq 10 7 68`; do
      touch $n
done  

# Imposta il primo tipo di "cavallo" che lo script deve disegnare.
TIPO_CAVALLO=2

#  Crea i file-posizione e i file-posta per ogni "cavallo".
#+ In questi file vengono registrati la posizione e il tipo del cavallo,
#+ nonché la relativa posta.
for CN in `seq 9`; do
      touch cavallo_${CN}_posizione
      touch posta_${CN}
      echo \-1 > cavallo_${CN}_posizione
      echo $TIPO_CAVALLO >>  cavallo_${CN}_posizione
      # Determina un handicap casuale per il cavallo.
       HANDICAP=`casuale_1_9`
      # Verifica che la funzione casuale_1_9 restituisca un valore valido.
      while ! echo $HANDICAP | grep [1-9] &> /dev/null; do
                HANDICAP=`casuale_1_9`
      done
      # Determina l'handicap del cavallo in ultima posizione. 
      CUP=`expr $HANDICAP \* 7 + 3`
      for FILE in `seq 10 7 $CUP`; do
            echo $CN >> $FILE
      done   
     
      # Calcola le poste.
      case $HANDICAP in 
              1) POSTA=`echo $HANDICAP \* 0.25 + 1.25 | bc`
                                 echo $POSTA > posta_${CN}
              ;;
              2 | 3) POSTA=`echo $HANDICAP \* 0.40 + 1.25 | bc`
                                       echo $POSTA > posta_${CN}
              ;;
              4 | 5 | 6) POSTA=`echo $HANDICAP \* 0.55 + 1.25 | bc`
                                             echo $POSTA > posta_${CN}
              ;; 
              7 | 8) POSTA=`echo $HANDICAP \* 0.75 + 1.25 | bc`
                                       echo $POSTA > posta_${CN}
              ;; 
              9) POSTA=`echo $HANDICAP \* 0.90 + 1.25 | bc`
                                  echo $POSTA > posta_${CN}
      esac


done


# Per visualizzare le poste.
visualizza_poste() {
tput cup 6 0
echo -ne '\E[30;42m'
for CN in `seq 9`; do
      echo "#$CN posta->" `cat posta_${CN}`
done
}

# Per disegnare i cavalli sulla linea di partenza.
disegna_cavalli() {
tput cup 6 0
echo -ne '\E[30;42m'
for CN in `seq 9`; do
      echo /\\$CN/\\"                               "
done
}

visualizza_poste

echo -ne '\E[47m'
# Attende la pressione di un tasto per dar inizio alla gara.
# La sequenza di escape '\E[?25l' disabilita il cursore.
tput cup 17 0
echo -e '\E[?25l'Premete il tasto [invio] per iniziare la gara...
read -s

#  Disabilita la normale visualizzazione del terminale.
#  In questo modo si evita che la pressione accidentale di qualche tasto
#+ possa "contaminare" lo schermo durante la gara.  
stty -echo

# --------------------------------------------------------
# La corsa ha inizio.

disegna_cavalli
echo -ne '\E[37;47m'
sposta_e_visualizza 18 1 $STRINGA80
echo -ne '\E[30m'
sposta_e_visualizza 18 1 Partenza...
sleep 1

# Imposta la posizione del traguardo.
POS_TRAGUARDO=74

# Determina l'ora di inizio gara.
ORA_PARTENZA=`date +%s`

# Variabile COL necessaria per il costrutto "while" successivo.
COL=0    

while [ $COL -lt $POS_TRAGUARDO ]; do
                   
          MUOVI_CAVALLO=0     
          
          # Verifica che la funzione casuale_1_9 restituisca un valore valido.
          while ! echo $MUOVI_CAVALLO | grep [1-9] &> /dev/null; do
                MUOVI_CAVALLO=`casuale_1_9`
          done
          
          # Determina i precedenti tipo e posizione del "cavallo randomizzato".
          TIPO_CAVALLO=`cat  cavallo_${MUOVI_CAVALLO}_posizione | tail -n 1`
          COL=$(expr `cat  cavallo_${MUOVI_CAVALLO}_posizione | head -n 1`) 
          
          AGG_POS=1
          #  Verifica se la posizione attuale corrisponde a una posizione di 
          #+ handicap. 
          if seq 10 7 68 | grep -w $COL &> /dev/null; then
                if grep -w $MUOVI_CAVALLO $COL &> /dev/null; then
                      AGG_POS=0
                      grep -v -w  $MUOVI_CAVALLO $COL > ${COL}_nuova
                      rm -f $COL
                      mv -f ${COL}_nuova $COL
                      else AGG_POS=1
                fi 
          else AGG_POS=1
          fi
          COL=`expr $COL + $AGG_POS`
          echo $COL >  cavallo_${MUOVI_CAVALLO}_posizione  #  Registra la nuova
                                                           #+ posizione.
                            
          # Scelta del tipo di cavallo da disegnare.         
          case $TIPO_CAVALLO in 
                1) TIPO_CAVALLO=2; DISEGNA_CAVALLO=disegna_cavallo_due
                ;;
                2) TIPO_CAVALLO=1; DISEGNA_CAVALLO=disegna_cavallo_uno 
          esac 
          # Registra il tipo corrente.      
          echo $TIPO_CAVALLO >>  cavallo_${MUOVI_CAVALLO}_posizione 
         
          #  Imposta a nero il colore del primo piano, 
          #+ a verde quello dello sfondo.
          echo -ne '\E[30;42m'
          
          # Sposta il cursore nella nuova posizione del cavallo.
          tput cup `expr $MUOVI_CAVALLO + 5`\
 `cat  cavallo_${MUOVI_CAVALLO}_posizione | head -n 1` 
          
          # Disegna il cavallo.
          $DISEGNA_CAVALLO
           usleep $USLEEP_ARG
          
           #  Quando tutti i cavalli hanno oltrepassato il campo corrispondente 
           #+ alla linea 16, vengono rivisualizzate le poste.          
           touch linea16
           if [ $COL = 16 ]; then
             echo $MUOVI_CAVALLO >> linea16  
           fi
           if [ `wc -l linea16 | cut -f1 -d " "` = 9 ]; then
               visualizza_poste
               : > linea16
           fi           
          
          # Determina il cavallo in prima posizione.
          PRIMA_POS=`cat *posizione | sort -n | tail -1`         
          
          # Imposta a bianco il colore dello sfondo.
          echo -ne '\E[47m'
          tput cup 17 0
          echo -n Leader della corsa: `grep -w $PRIMA_POS *posizione |\
 cut -c9`"                              "           

done  

# Determina l'ora d'arrivo.
ORA_ARRIVO=`date +%s`

# Imposta a verde il colore dello sfondo e abilita il testo intermittente.
echo -ne '\E[30;42m'
echo -en '\E[5m'

# Fa "lampeggiare" il cavallo vincitore.
tput cup `expr $MUOVI_CAVALLO + 5`\
 `cat  cavallo_${MUOVI_CAVALLO}_posizione | head -n 1`
$DISEGNA_CAVALLO

# Disabilita il testo intermittente.
echo -en '\E[25m'

# Imposta a bianco i colori del primo piano e dello sfondo.
echo -ne '\E[37;47m'
sposta_e_visualizza 18 1 $STRINGA80

# Imposta a nero il colore del primo piano.
echo -ne '\E[30m'

# Vincitore intermittente.
tput cup 17 0
echo -e "\E[5mVINCITORE: $MUOVI_CAVALLO\E[25m""  Posta: \
`cat posta_${MUOVI_CAVALLO}`" "  Durata della gara:\
 `expr $ORA_ARRIVO - $ORA_PARTENZA` secondi"

# Ripristina il cursore e i colori precedenti.
echo -en "\E[?25h"
echo -en "\E[0m"

# Ripristina la normale visualizzazione.
stty echo

# Cancella la directory temporanea.
rm -rf $CORSA_CAVALLI_DIR_TMP

tput cup 19 0

exit 0

#* La verifica per usleep è stata da me aggiunta, su autorizzazione
#+ dell'autore dello script, perché questa utility non fa parte 
#+ dell'installazione di default su alcune distribuzioninon Linux.
#  Un grazie a Stefano Palmieri anche per l'autorizzazione a tutte le modifiche
#+ che sono state necessarie per "italianizzare" lo script. [N.d.T.]  

Vedi anche Esempio A-22.

Attenzione

Esiste, comunque, un grosso problema. Le sequenze di escape ANSI non sono assolutamente portabili. Ciò che funziona bene su certi emulatori di terminale (o sulla console) potrebbe funzionare in modo diverso (o per niente) su altri. Uno script "a colori" che appare sbalorditivo sulla macchina del suo autore, potrebbe produrre un output illeggibile su quella di qualcun altro. Questo fatto compromette grandemente l'utilità di "colorazione" degli script, relegando questa tecnica allo stato di semplice espediente o addirittura di "bazzecola".

L'utility color di Moshe Jacobson (http://runslinux.net/projects.html#color) semplifica considerevolmente l'uso delle sequenze di escape ANSI. Essa sostituisce i goffi costrutti appena trattati con una sintassi chiara e logica.

Anche Henry/teikedvl ha creato un'utility (http://scriptechocolor.sourceforge.net/) che semplifica la realizzazione di script che "colorano".

Note

[1]

Naturalmente, ANSI è l'acronimo di American National Standards Institute. Quest'imponente struttura ratifica e difende numerosi standard tecnici e industriali.