Les séquences d'échappement d'ANSI [122] permettent de régler les attributs de l'écran, tels que le texte en gras et la couleur d'affichage et de fond. Les fichiers batch DOS utilisaient communément les séquences d'échappement ANSI pour les affichages couleur, comme peuvent le faire les scripts Bash.
Exemple 36.11. Une base de données d'adresses « colorisée »
#!/bin/bash # ex30a.sh : Version "colorisée" de ex30.sh. # Base de données d'adresses. clear # Efface l'écran. echo -n " " echo -e '\E[37;44m'"\033[1mListe de contacts\033[0m" # Blanc sur fond bleu echo; echo echo -e "\033[1mChoisissez une des personnes suivantes :\033[0m" # Bold tput sgr0 echo "(Entrez seulement les premières lettres du nom)" echo echo -en '\E[47;34m'"\033[1mE\033[0m" # Bleu tput sgr0 # Réinitialise les couleurs à la #+ "normale." 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" # Vert tput sgr0 echo "mith, Julie" echo -en '\E[47;31m'"\033[1mZ\033[0m" # Rouge tput sgr0 echo "ane, Morris" echo read personne case "$personne" in # Notez que la variable est entre guillemets. "E" | "e" ) # Accepte une entrée en majuscule ou minuscule. 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 "Business partner & old friend" ;; "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 "Girlfriend" echo "Birthday: Feb. 11" ;; # Ajoutez de l'info pour Smith & Zane plus tard. * ) # Option par défaut. # Une entrée vide (en appuyant uniquement sur RETURN) vient ici aussi. echo echo "Pas encore dans la base de données." ;; esac tput sgr0 # Réinitialisation des couleurs à la #+ "normale". echo exit 0
Exemple 36.12. Dessiner une boîte
#!/bin/bash # Draw-box.sh: Drawing a box using ASCII characters. # Script by Stefano Palmeri, with minor editing by document author. # Minor edits suggested by Jim Angstadt. # Used in the ABS Guide with permission. ###################################################################### ### draw_box function doc ### # The "draw_box" function lets the user #+ draw a box in a terminal. # # Usage: draw_box ROW COLUMN HEIGHT WIDTH [COLOR] # ROW and COLUMN represent the position #+ of the upper left angle of the box you're going to draw. # ROW and COLUMN must be greater than 0 #+ and less than current terminal dimension. # HEIGHT is the number of rows of the box, and must be > 0. # HEIGHT + ROW must be <= than current terminal height. # WIDTH is the number of columns of the box and must be > 0. # WIDTH + COLUMN must be <= than current terminal width. # # E.g.: If your terminal dimension is 20x80, # draw_box 2 3 10 45 is good # draw_box 2 3 19 45 has bad HEIGHT value (19+2 > 20) # draw_box 2 3 18 78 has bad WIDTH value (78+3 > 80) # # COLOR is the color of the box frame. # This is the 5th argument and is optional. # 0=black 1=red 2=green 3=tan 4=blue 5=purple 6=cyan 7=white. # If you pass the function bad arguments, #+ it will just exit with code 65, #+ and no messages will be printed on stderr. # # Clear the terminal before you start to draw a box. # The clear command is not contained within the function. # This allows the user to draw multiple boxes, even overlapping ones. ### end of draw_box function doc ### ###################################################################### draw_box(){ #=============# HORZ="-" VERT="|" CORNER_CHAR="+" MINARGS=4 E_BADARGS=65 #=============# if [ $# -lt "$MINARGS" ]; then # If args are less than 4, exit. exit $E_BADARGS fi # Looking for non digit chars in arguments. # Probably it could be done better (exercise for the reader?). if echo $@ | tr -d [:blank:] | tr -d [:digit:] | grep . &> /dev/null; then exit $E_BADARGS fi BOX_HEIGHT=`expr $3 - 1` # -1 correction needed because angle char "+" BOX_WIDTH=`expr $4 - 1` #+ is a part of both box height and width. T_ROWS=`tput lines` # Define current terminal dimension T_COLS=`tput cols` #+ in rows and columns. if [ $1 -lt 1 ] || [ $1 -gt $T_ROWS ]; then # Start checking if arguments exit $E_BADARGS #+ are correct. fi if [ $2 -lt 1 ] || [ $2 -gt $T_COLS ]; then exit $E_BADARGS fi if [ `expr $1 + $BOX_HEIGHT + 1` -gt $T_ROWS ]; then exit $E_BADARGS fi if [ `expr $2 + $BOX_WIDTH + 1` -gt $T_COLS ]; then exit $E_BADARGS fi if [ $3 -lt 1 ] || [ $4 -lt 1 ]; then exit $E_BADARGS fi # End checking arguments. plot_char(){ # Function within a function. echo -e "\E[${1};${2}H"$3 } echo -ne "\E[3${5}m" # Set box frame color, if defined. # start drawing the box count=1 # Draw vertical lines using for (( r=$1; count<=$BOX_HEIGHT; r++)); do #+ plot_char function. plot_char $r $2 $VERT let count=count+1 done count=1 c=`expr $2 + $BOX_WIDTH` for (( r=$1; count<=$BOX_HEIGHT; r++)); do plot_char $r $c $VERT let count=count+1 done count=1 # Draw horizontal lines using for (( c=$2; count<=$BOX_WIDTH; c++)); do #+ plot_char function. plot_char $1 $c $HORZ let count=count+1 done count=1 r=`expr $1 + $BOX_HEIGHT` for (( c=$2; count<=$BOX_WIDTH; c++)); do plot_char $r $c $HORZ let count=count+1 done plot_char $1 $2 $CORNER_CHAR # Draw box angles. plot_char $1 `expr $2 + $BOX_WIDTH` $CORNER_CHAR plot_char `expr $1 + $BOX_HEIGHT` $2 $CORNER_CHAR plot_char `expr $1 + $BOX_HEIGHT` `expr $2 + $BOX_WIDTH` $CORNER_CHAR echo -ne "\E[0m" # Restore old colors. P_ROWS=`expr $T_ROWS - 1` # Put the prompt at bottom of the terminal. echo -e "\E[${P_ROWS};1H" } # Now, let's try drawing a box. clear # Clear the terminal. R=2 # Row C=3 # Column H=10 # Height W=45 # Width col=1 # Color (red) draw_box $R $C $H $W $col # Draw the box. exit 0 # Exercise: # -------- # Add the option of printing text within the drawn box.
La séquence d'échappement ANSI la plus simple et peut-être la plus utile est du texte gras, \033[1m ... \033[0m. \033 représente un escape, « [1 » active l'attribut gras, alors que « [0 » la désactive. « m » termine chaque terme de la séquence d'échappement.
bash$ echo -e "\033[1mCeci est un texte en gras.\033[0m"
Une séquence d'échappement similaire active l'attribut de soulignement (sur un rxvt et un aterm).
bash$ echo -e "\033[4mCe texte est souligné.\033[0m"
Avec un echo, l'option -e active les séquences d'échappement.
D'autres séquences d'échappement modifie le texte et/ou la couleur du fond.
bash$ echo -e '\E[34;47mCeci est affiché en bleu.'; tput sgr0 bash$ echo -e '\E[33;44m'"texte jaune sur fond bleu"; tput sgr0 bash$ echo -e '\E[1;33;44m'"texte jaune en gras sur fond bleu"; tput sgr0
Il est généralement conseillé d'initialiser l'attribut gras pour le texte coloré avec des teintes claires.
tput sgr0 restaure les paramétrages du terminal en normal. L'omettre laisse toute sortie ultérieure à partir de ce terminal en bleu.
Comme tput sgr0 échoue lors de la restauration des paramètres du terminal sous certaines circonstances, echo -ne \E[0m pourrait être un meilleur choix.
Les nombres dans la table suivante fonctionnent pour un terminal rxvt. Les résultats peuvent varier pour d'autres émulateurs de terminaux.
Tableau 36.1. Nombres représentant les couleurs des séquences d'échappement
Couleur | Avant-plan | Arrière-plan |
---|---|---|
noir | 30 | 40 |
rouge | 31 | 41 |
vert | 32 | 42 |
jaune | 33 | 43 |
bleu | 34 | 44 |
magenta | 35 | 45 |
cyan | 36 | 46 |
blanc | 37 | 47 |
Exemple 36.13. Afficher du texte colorisé
#!/bin/bash # color-echo.sh : Affiche des messages texte en couleur. # Modifier ce script pour vos besoins propres. # C'est plus facile que de coder manuellement les couleurs. noir='\E[30;47m' rouge='\E[31;47m' vert='\E[32;47m' jaune='\E[33;47m' bleu='\E[34;47m' magenta='\E[35;47m' cyan='\E[36;47m' blanc='\E[37;47m' alias init="tput sgr0" # Initialise les attributs texte à la normale #+ sans effacer l'écran. cecho () # Echo couleur. # Argument $1 = message # Argument $2 = couleur { local msg_par_defaut="Pas de message." # N'a pas réellement besoin d'être une variable # locale. message=${1:-$msg_par_defaut}# Message par défaut. couleur=${2:-$noir} # Noir par défaut si non spécifié. echo -e "$color" echo "$message" init # Retour à la normale. return } # Maintenant, essayons-le. # ---------------------------------------------------- cecho "Je me sens bleu..." $bleu cecho "Le magenta ressemble plus à du violet." $magenta cecho "Vert avec envie." $vert cecho "Vous voyez rouge ?" $rouge cecho "Cyan, mieux connu sous le nom d'aqua." $cyan cecho "Pas de couleur précisée (noir par défaut)." # Argument $color manquant. cecho "Couleur \"vide\" passée (noir par défaut)." "" # Argument $color vide. cecho # Arguments $message et $color manquants. cecho "" "" # Arguments $message et $color vides. # ---------------------------------------------------- echo exit 0 # Exercices : # ---------- # 1) Ajouter l'attribut "gras" à la fonction 'cecho ()'. # 2) Ajouter des options pour des fonds colorés.
Exemple 36.14. Un jeu de « courses de chevaux »
#!/bin/bash # horserace.sh: Very simple horserace simulation. # Author: Stefano Palmeri # Used with permission. ################################################################ # Goals of the script: # playing with escape sequences and terminal colors. # # Exercise: # Edit the script to make it run less randomly, #+ set up a fake betting shop . . . # Um . . . um . . . it's starting to remind me of a movie . . . # # The script gives each horse a random handicap. # The odds are calculated upon horse handicap #+ and are expressed in European(?) style. # E.g., odds=3.75 means that if you bet $1 and win, #+ you receive $3.75. # # The script has been tested with a GNU/Linux OS, #+ using xterm and rxvt, and konsole. # On a machine with an AMD 900 MHz processor, #+ the average race time is 75 seconds. # On faster computers the race time would be lower. # So, if you want more suspense, reset the USLEEP_ARG variable. # # Script by Stefano Palmeri. ################################################################ E_RUNERR=65 # Check if md5sum and bc are installed. if ! which bc &> /dev/null; then echo bc is not installed. echo "Can\'t run . . . " exit $E_RUNERR fi if ! which md5sum &> /dev/null; then echo md5sum is not installed. echo "Can\'t run . . . " exit $E_RUNERR fi # Set the following variable to slow down script execution. # It will be passed as the argument for usleep (man usleep) #+ and is expressed in microseconds (500000 = half a second). USLEEP_ARG=0 # Clean up the temp directory, restore terminal cursor and #+ terminal colors -- if script interrupted by Ctl-C. trap 'echo -en "\E[?25h"; echo -en "\E[0m"; stty echo;\ tput cup 20 0; rm -fr $HORSE_RACE_TMP_DIR' TERM EXIT # See the chapter on debugging for an explanation of 'trap.' # Set a unique (paranoid) name for the temp directory the script needs. HORSE_RACE_TMP_DIR=$HOME/.horserace-`date +%s`-`head -c10 /dev/urandom \ | md5sum | head -c30` # Create the temp directory and move right in. mkdir $HORSE_RACE_TMP_DIR cd $HORSE_RACE_TMP_DIR # This function moves the cursor to line $1 column $2 and then prints $3. # E.g.: "move_and_echo 5 10 linux" is equivalent to #+ "tput cup 4 9; echo linux", but with one command instead of two. # Note: "tput cup" defines 0 0 the upper left angle of the terminal, #+ echo defines 1 1 the upper left angle of the terminal. move_and_echo() { echo -ne "\E[${1};${2}H""$3" } # Function to generate a pseudo-random number between 1 and 9. random_1_9 () { head -c10 /dev/urandom | md5sum | tr -d [a-z] | tr -d 0 | cut -c1 } # Two functions that simulate "movement," when drawing the horses. draw_horse_one() { echo -n " "//$MOVE_HORSE// } draw_horse_two(){ echo -n " "\\\\$MOVE_HORSE\\\\ } # Define current terminal dimension. N_COLS=`tput cols` N_LINES=`tput lines` # Need at least a 20-LINES X 80-COLUMNS terminal. Check it. if [ $N_COLS -lt 80 ] || [ $N_LINES -lt 20 ]; then echo "`basename $0` needs a 80-cols X 20-lines terminal." echo "Your terminal is ${N_COLS}-cols X ${N_LINES}-lines." exit $E_RUNERR fi # Start drawing the race field. # Need a string of 80 chars. See below. BLANK80=`seq -s "" 100 | head -c80` clear # Set foreground and background colors to white. echo -ne '\E[37;47m' # Move the cursor on the upper left angle of the terminal. tput cup 0 0 # Draw six white lines. for n in `seq 5`; do echo $BLANK80 # Use the 80 chars string to colorize the terminal. done # Sets foreground color to black. echo -ne '\E[30m' move_and_echo 3 1 "START 1" move_and_echo 3 75 FINISH move_and_echo 1 5 "|" move_and_echo 1 80 "|" move_and_echo 2 5 "|" move_and_echo 2 80 "|" move_and_echo 4 5 "| 2" move_and_echo 4 80 "|" move_and_echo 5 5 "V 3" move_and_echo 5 80 "V" # Set foreground color to red. echo -ne '\E[31m' # Some ASCII art. move_and_echo 1 8 "..@@@..@@@@@...@@@@@.@...@..@@@@..." move_and_echo 2 8 ".@...@...@.......@...@...@.@......." move_and_echo 3 8 ".@@@@@...@.......@...@@@@@.@@@@...." move_and_echo 4 8 ".@...@...@.......@...@...@.@......." move_and_echo 5 8 ".@...@...@.......@...@...@..@@@@..." move_and_echo 1 43 "@@@@...@@@...@@@@..@@@@..@@@@." move_and_echo 2 43 "@...@.@...@.@.....@.....@....." move_and_echo 3 43 "@@@@..@@@@@.@.....@@@@...@@@.." move_and_echo 4 43 "@..@..@...@.@.....@.........@." move_and_echo 5 43 "@...@.@...@..@@@@..@@@@.@@@@.." # Set foreground and background colors to green. echo -ne '\E[32;42m' # Draw eleven green lines. tput cup 5 0 for n in `seq 11`; do echo $BLANK80 done # Set foreground color to black. echo -ne '\E[30m' tput cup 5 0 # Draw the fences. echo "++++++++++++++++++++++++++++++++++++++\ ++++++++++++++++++++++++++++++++++++++++++" tput cup 15 0 echo "++++++++++++++++++++++++++++++++++++++\ ++++++++++++++++++++++++++++++++++++++++++" # Set foreground and background colors to white. echo -ne '\E[37;47m' # Draw three white lines. for n in `seq 3`; do echo $BLANK80 done # Set foreground color to black. echo -ne '\E[30m' # Create 9 files to stores handicaps. for n in `seq 10 7 68`; do touch $n done # Set the first type of "horse" the script will draw. HORSE_TYPE=2 # Create position-file and odds-file for every "horse". #+ In these files, store the current position of the horse, #+ the type and the odds. for HN in `seq 9`; do touch horse_${HN}_position touch odds_${HN} echo \-1 > horse_${HN}_position echo $HORSE_TYPE >> horse_${HN}_position # Define a random handicap for horse. HANDICAP=`random_1_9` # Check if the random_1_9 function returned a good value. while ! echo $HANDICAP | grep [1-9] &> /dev/null; do HANDICAP=`random_1_9` done # Define last handicap position for horse. LHP=`expr $HANDICAP \* 7 + 3` for FILE in `seq 10 7 $LHP`; do echo $HN >> $FILE done # Calculate odds. case $HANDICAP in 1) ODDS=`echo $HANDICAP \* 0.25 + 1.25 | bc` echo $ODDS > odds_${HN} ;; 2 | 3) ODDS=`echo $HANDICAP \* 0.40 + 1.25 | bc` echo $ODDS > odds_${HN} ;; 4 | 5 | 6) ODDS=`echo $HANDICAP \* 0.55 + 1.25 | bc` echo $ODDS > odds_${HN} ;; 7 | 8) ODDS=`echo $HANDICAP \* 0.75 + 1.25 | bc` echo $ODDS > odds_${HN} ;; 9) ODDS=`echo $HANDICAP \* 0.90 + 1.25 | bc` echo $ODDS > odds_${HN} esac done # Print odds. print_odds() { tput cup 6 0 echo -ne '\E[30;42m' for HN in `seq 9`; do echo "#$HN odds->" `cat odds_${HN}` done } # Draw the horses at starting line. draw_horses() { tput cup 6 0 echo -ne '\E[30;42m' for HN in `seq 9`; do echo /\\$HN/\\" " done } print_odds echo -ne '\E[47m' # Wait for a enter key press to start the race. # The escape sequence '\E[?25l' disables the cursor. tput cup 17 0 echo -e '\E[?25l'Press [enter] key to start the race... read -s # Disable normal echoing in the terminal. # This avoids key presses that might "contaminate" the screen #+ during the race. stty -echo # -------------------------------------------------------- # Start the race. draw_horses echo -ne '\E[37;47m' move_and_echo 18 1 $BLANK80 echo -ne '\E[30m' move_and_echo 18 1 Starting... sleep 1 # Set the column of the finish line. WINNING_POS=74 # Define the time the race started. START_TIME=`date +%s` # COL variable needed by following "while" construct. COL=0 while [ $COL -lt $WINNING_POS ]; do MOVE_HORSE=0 # Check if the random_1_9 function has returned a good value. while ! echo $MOVE_HORSE | grep [1-9] &> /dev/null; do MOVE_HORSE=`random_1_9` done # Define old type and position of the "randomized horse". HORSE_TYPE=`cat horse_${MOVE_HORSE}_position | tail -n 1` COL=$(expr `cat horse_${MOVE_HORSE}_position | head -n 1`) ADD_POS=1 # Check if the current position is an handicap position. if seq 10 7 68 | grep -w $COL &> /dev/null; then if grep -w $MOVE_HORSE $COL &> /dev/null; then ADD_POS=0 grep -v -w $MOVE_HORSE $COL > ${COL}_new rm -f $COL mv -f ${COL}_new $COL else ADD_POS=1 fi else ADD_POS=1 fi COL=`expr $COL + $ADD_POS` echo $COL > horse_${MOVE_HORSE}_position # Store new position. # Choose the type of horse to draw. case $HORSE_TYPE in 1) HORSE_TYPE=2; DRAW_HORSE=draw_horse_two ;; 2) HORSE_TYPE=1; DRAW_HORSE=draw_horse_one esac echo $HORSE_TYPE >> horse_${MOVE_HORSE}_position # Store current type. # Set foreground color to black and background to green. echo -ne '\E[30;42m' # Move the cursor to new horse position. tput cup `expr $MOVE_HORSE + 5` \ `cat horse_${MOVE_HORSE}_position | head -n 1` # Draw the horse. $DRAW_HORSE usleep $USLEEP_ARG # When all horses have gone beyond field line 15, reprint odds. touch fieldline15 if [ $COL = 15 ]; then echo $MOVE_HORSE >> fieldline15 fi if [ `wc -l fieldline15 | cut -f1 -d " "` = 9 ]; then print_odds : > fieldline15 fi # Define the leading horse. HIGHEST_POS=`cat *position | sort -n | tail -1` # Set background color to white. echo -ne '\E[47m' tput cup 17 0 echo -n Current leader: `grep -w $HIGHEST_POS *position | cut -c7`\ " " done # Define the time the race finished. FINISH_TIME=`date +%s` # Set background color to green and enable blinking text. echo -ne '\E[30;42m' echo -en '\E[5m' # Make the winning horse blink. tput cup `expr $MOVE_HORSE + 5` \ `cat horse_${MOVE_HORSE}_position | head -n 1` $DRAW_HORSE # Disable blinking text. echo -en '\E[25m' # Set foreground and background color to white. echo -ne '\E[37;47m' move_and_echo 18 1 $BLANK80 # Set foreground color to black. echo -ne '\E[30m' # Make winner blink. tput cup 17 0 echo -e "\E[5mWINNER: $MOVE_HORSE\E[25m"" Odds: `cat odds_${MOVE_HORSE}`"\ " Race time: `expr $FINISH_TIME - $START_TIME` secs" # Restore cursor and old colors. echo -en "\E[?25h" echo -en "\E[0m" # Restore echoing. stty echo # Remove race temp directory. rm -rf $HORSE_RACE_TMP_DIR tput cup 19 0 exit 0
Voir aussi l'Exemple A.21, « Coloriser du texte en utilisant les fonctions de hachage », Exemple A.44, « Création de devoirs sur la programmation shell en général », Exemple A.52, « Voir tour à tour tous les fonds colorés existants » et Exemple A.40, « Pétales autour d'une rose ».
Tout ceci pose néanmoins un problème majeur. Les séquences d'échappement ANSI ne sont pas du tout portables. Celles qui fonctionnent bien sur certains émulateurs de terminal (ou sur la console) peuvent fonctionner différemment, voire pas du tout, sur d'autres. Un script « colorisé » qui s'affiche magnifiquement sur la machine de l'auteur du script peut produire un affichage illisible chez quelqu'un d'autre. Ceci compromet quelque peu l'utilité de la « colorisation » des scripts, et pourrait reléguer cette technique au statut de gadget. Les scripts en couleurs sont probablement inappropriés dans un cadre commercial, i.e. leur emploi sera peut-être critiqué par votre supérieur.
L'utilitaire ansi-color de Alister (basé sur l'utilitaire de colorisation de Moshe Jacobson) simplifie considérablement l'utilisation des séquences d'échappement ANSI. Il substitue une syntaxe propre et claire aux expressions maladroites discutées ci-dessus.
Henry/teikedvl a également créé un outil (http://scriptechocolor.sourceforge.net/) pour simplifier la création de scripts colorisés.
[122] ANSI est, bien sûr, l'acronyme pour « American National Standards Institute ». Ce corps auguste établit et maintient différents standards techniques et industriels.