Précédent Index Suivant

2.6   L'interprète de commandes sh

2.6.1   Fichiers de commandes

sh est l'interprète de commandes. Il peut se mettre en oeuvre lui-même. Ainsi
 sh <essai.sh >resultat 
correspond au schéma global


Les commandes présentes dans le fichier essai.sh (l'extension .sh signifie que le fichier contient des commandes destinées à sh) seront exécutées et leur résultat sera placé dans le fichier resultat.

Une autre forme existe pour exécuter un fichier de commandes :
 sh fichier 
La différence réside dans les valeurs de la commande intrinsèque read qui lit une ligne dans le flux entrant (essai.sh dans le premier cas et /dev/tty dans le second).

Il est tellement usuel de possèder des fichiers de commandes que l'on peut en demander l'exécution en nommant seulement le fichier à condition de l'avoir rendu exécutable (cf. chmod). Ainsi
 fichier arguments 
conduit-il à


De fait puisqu'un programme exécutable est aussi archivé comme un fichier, l'interprète de commandes lorsqu'il cherche à évaluer une commande comme
 fichier arguments... 
regarde tout d'abord si le fichier possède l'attribut exécutable puis s'il correspond à des instructions binaires ou à un texte. Suivant le cas il lance l'exécution du programme ou bien celle d'une tâche basée sur sh lisant ce fichier considéré comme une suite de commandes. Cette tâche se terminera lorsque le fichier sera épuisé.

L'interprète de commandes (sh) offre des primitives de programmation structurée : La fin de ligne est considérée comme une fin de commandes ainsi que le point-virgule. On pourrait aussi écrire comme suit les exemples précédents :
if f77 essai.f ;  then echo fini ;  else echo erreur ;  fi  
et
{ ls -Ral 
  echo fini
            }  

La conditionnelle, ainsi que les primitives while et until, ne se peuvent concevoir que parce que chaque tâche qui s'achève retourne à son initiatrice un code: Attention, sous sh les valeurs de vérité sont représentées à l'inverse des conventions usuelles. Pour C, Vrai est 1 et Faux, 0. Pour Pascal, Faux est avant Vrai et usuellement représenté aussi par 0.

La commande exit permet d'achever une suite de commandes en imposant le code de retour. Par défaut ce code est nul. Par exemple
if f77 essai.f
then exit 1
     echo fini    
else 
     echo "c'est bien erroné"
     exit   # comme exit 0 !
fi  

Le retour sera Faux si la compilation s'est bien passé (et le message fini ne sera pas produit). Dans le cas contraire c'est le message c'est bien erroné qui sera engendré et la valeur logique de retour sera Vrai !

2.6.2   Autres possibilités

De nombreuses autres possibilités existent, qui font de l'interprète de commandes un véritable interprète de langage : Le langage shell! La notion de variable existe. Ainsi :
 prg=/u/untel/f77 
déclare une variable nommée prg ayant pour valeur la chaine de caractères /u/untel/f77. On peut utiliser cette variable en la préfixant du symbole $.
 f77 $prg/e.f 
est équivalent à
 f77 /u/untel/f77/e.f 
C'est une simple substitution textuelle qui ignore la structure même des commandes. Ainsi
$ cde1='cat /'
$ cde2='o "Bonjour"'
$ ech$cde2
Bonjour
$ ${cde1}u/untel/f77/test.$cde2 
listera le fichier /u/untel/f77/test.o et le fichier Bonjour.

Certaines variables prédéfinies existent comme $0,$1, $2...$9, $PATH, $USER ... Les dix premières permettent de nommer l'argument de rang correspondant lors de l'appel à une commande. Ainsi peut-on faire des « sous-programmes » pouvant prendre facilement jusqu'à neuf arguments ($0 est le nom du sous-programme appelé). On peut mettre en un fichier nommé compil le programme (qu'UNIX nomme script!)

suivant :
if f77 $1
then exit
else { print $1 & echo $1 est erronné
                  exit 1 
                  }
fi  
puis appeler ce fichier par la commande
 compil e.f 
$1 sera connue comme étant la chaine de caractères e.f durant tout le déroulement de la commande compil. $0 sera compil, les autres $i seront vides. compil compilera e.f et en cas d'erreur $PATH est l'ensemble des chemins d'accès où chercher les fichiers exécutables pour un utilisateur (qui a son nom contenu dans la variable $USER). Par exemple, lors de la soumission d'une commande
 fichier arguments 
sh recherchera fichier dans tous les répertoires mentionnés dans $PATH et ceux-là seulement. Si $PATH est vide, vous ne pourrez vraisemblablement pas faire grand chose! Usuellement $PATH contient
 :/usr/local:/bin:/usr/bin:/usr/ucb 

Les répertoires sont séparés par :. Un répertoire vide désigne le répertoire courant. Ici, une commande mentionnant fichier est recherchée On peut bien sûr étendre $PATH en écrivant par exemple
 PATH=$PATH:/u/queinnec/cmds 
(cmds est le répertoire où je regroupe mes commandes).

$MAIL contient le nom du fichier boîte à lettres que l'interprète scrutera toutes les cinq minutes afin de vous prévenir de l'éventuelle arrivée de messages.

Attention, une variable est locale à la tâche où elle a été définie. Pour qu'elle soit connue des tâches filles qui viendraient à être créées, elle doit être exportée par la commande
export variable, variable ... 
En aucun cas vous ne pourrez modifier la valeur d'une variable d'une tâche ancêtre.

Par exemple, pour que la modification de PATH précédement faite soit connue de toute fille qui viendrait à être engendrée, il faudra exporter cette variable, et pour cela écrire :
export PATH 

Un autre mécanisme bien utile est que le sh de connexion exécute systématiquement, s'il le trouve dans le répertoire initial (valeur de HOME),le fichier de commandes .profile. .profile peut donc contenir toutes les initialisations personnelles que vous pourriez souhaiter. À titre d'exemple, voici mon .profile personnel [Celui de 1985!]
#
#       variables diverses
#
umask 022               # chmod go=r u=rw
PATH=":$HOME/cmds:/usr/local:/bin:/usr/bin:/usr/ucb:/etc"
#                        diverses options
SITE='Ensta'    # nom du site 
SPEED=300       # Bauds
ED=emin         # Le préféré sur ce site
MORE='-cf'
#                       Les invites
if test $TERM = FT
then    PS1='\\0315\\031`<' # dessine un MU suivi d'un OMEGA
else    PS1="$SITE<- "
fi
PS2='Suite <- '
#                       message de bienvenue
echo "B I E N V E N U E sur $SITE"
#
trap ". $HOME/.eliforp" 0     # .logout en quelque sorte !
#
stty lnext "undef" nxpage 'undef' nxhalf 'u' 
stty nxline 'u' flush 'u' erase '^H' kill '^U' 
stty werase '^W' rprnt '^R' intr '^?' quit '^\\' 
stty eof '^D' -pageen -pageon ctlecho
#                                courrier automatique
MAIL=/usr/spool/mail/$USER
if test -s $MAIL        
then    echo "$PS1 mail"
        mail
fi
# les exportations
export MORE ED MAIL SITE SPEED TERM PATH PS1 PS2 USER SHELL  

2.6.3   Expansion

Le mécanisme d'expansion est une des plus heureuses caractéristiques de sh. L'expansion permet de nommer simplement des groupes de fichiers. Elle se fonde principalement sur l'emploi de deux caractères : ? et *. Si le répertoire local (cf. le nom local) contient les fichiers :
a       ab      acb     aard    att     itt
t       t1      t2      t3      t6      t7       
alors On peut facilement voir le résultat d'une expansion grâce à echo
 echo *t* 
provoque
att     itt     t       t1      t2      t3      t6      t7       

D'autres expanseurs plus spécifiques existent comme
 t*[2-5] 
qui sélectionne les fichiers dont le nom commence par t et qui se terminent par un chiffre compris entre 2 et 5. Soient pour l'exemple précédent, t2 et t3 Cette expansion est faite de façon intelligente suivant les répertoires concernés. Ainsi
 echo ../pascal/t* 
expansera la spécification t* dans le répertoire pascal, frère du répertoire courant.

2.6.4   Déroulement

Lors de l'analyse d'une commande, la substitution de variables est effectuée en premier puis viennent les expansions mais, attention, le premier terme de la commande ne doit pas subir d'expansion. Ce premier mot est soit une commande intrinsèque soit un nom de fichier, Les mots suivants, c'est-à-dire des séquences de lettres séparées par des blancs ou des tabulations ou sauts à la ligne (ou, plus exactement, les caractères figurant dans la valeur de la variable IFS) sont alors ses arguments. Les répertoires figurant dans PATH sont alors scrutés séquentiellement afin d'y rechercher un fichier dont le nom est celui du premier mot et qui sera, si trouvé, lancé.

Tout ce qui précède n'est qu'une présentation succincte de l'interprète de commandes sh. D'autres existent, plus élaborés, qui ont pour nom csh, nsh, vsh, tcsh, cwsh...Tout interprète a ses détracteurs comme ses prosélytes ! Mais dans tous les cas ce ne sont que des programmes au dessus du coeur d'UNIX et tous peuvent s'exécuter en parallèle pour le bonheur de chacun. La variable SHELL vous renseignera sur votre interprète de commandes courant.

Vous êtes vivement invité à méditer les quelques sept pages de la documentation standard UNIX décrivant sh. ainsi qu'à étudier les fichiers de commandes qui sont accessibles (par exemple sous /usr/local).
Précédent Index Suivant