PRECEDENT | SOMMAIRE | SUIVANT |
Un système d'exploitation temps partagé est reconnu par son caractère interactif géré par l'interprète de commandes. On a vu que le shell exécute deux sortes de commandes: les commandes externes correspondant à un fichier et provoquant la création d'un nouveau processus, et les commandes internes qui sont directement interprétées par le shell. Ce sont elles qui font d'un shell un véritable outil de travail qui a aussi la puissance d'un véritable langage de programmation.
Un fichier script, et un fichier texte qui a le caractère exécutable. Il contient une liste de lignes commandes à exécuter en séquence et d'un seul trait. En effet, on peut avoir des situations où l'on aimerait exécuter toujours une même série de commandes et il est fâcheux d'avoir à les refaire à chaque moment. Il est alors intéressant de placer ces commandes dans un fichier et l'exécuter à la demande en tapant son nom qui devient ainsi une nouvelle commande. D'ailleurs les fichiers .login et .cshrc en sont des exemples particuliers. Voici un exemple de fichier script. Il affiche une fortune (maximes définies par les utilisateurs UNIX et fournies avec le système) et la rajoute dans une liste avec des lignes de séparation
% cat cookie
# Affichage et sauvegarde de fortunes ...
/usr/demo/games/fortune > t
cat t
echo "---------------------------------" >> mesFortunes
cat t >> mesFortunes
echo "-------------------------------- " >> mesFortunes
unalias rm
rm t
%
Pour exécuter un fichier script, il faut lui donner le mode x par
% chmod u+x script
sinon on peut l'exécuter (sous csh) par
% source script
Par ailleurs, le premier caractère du fichier doit être # si le fichier contient du code Cshell. Car en effet, il existe des différences, pas toujours légères, entre le code Cshell, Korn shell ou Bourne shell. Noter au passage que le caractère #, introduit aussi une ligne commentaire.
Remarque: Un fichier script donne lieu parfois
a un sous-shell qui l'exécute. Le tableau suivant
indique de façon résumée comment
exécuter un script. Soit monScript un fichier
script a exécuter. L'interprète courant est
supposé toujours csh.
Commande | Propriété du Fichier Script | Interprète du Fichier Script |
---|---|---|
% csh monScript
% monScript % monScript % source monScript % exec monScript |
Fichier texte
Fichier texte exécutable, # en début Fichier texte exécutable, sans # en
début Fichier texte Fichier texte exécutable |
Un sous shell csh
Un sous shell csh Un sous shell sh Le csh courant Un sous shell csh |
Dans le dernier cas, la session est quittée en fin de fichier script car le shell de lancement est recouvert par le processus associé au script. Noter aussi qu'on peut interpréter un script par le shell qu'on veut en mettant une première ligne
#! nomShell
et en exécutant le script par son nom.
nomShell est sh, csh ou
ksh.
#! /bin/sh
#! /bin/ksh
Le code doit bien sûr correspondre car il existe quelques différences syntaxiques et certaines commandes internes varient.
remarque: En terme UNIX, #!, servent a indiquer de facon générale le chemin du programme qui interpretera les lignes qui suivent dans le fichier. L'exemple suivant est un programme PERL qui imprime Hello World :
#!/usr/local/bin/perl
$foo="Hello World";
print $foo
Les structures de contrôle classiques facilitent la programmation des fichiers scripts qui deviennent de véritables procédures. La syntaxe, assez rigide parfois (e.g. les occurrences de la plupart des mots clés apparaissent seules dans une ligne) est proche du langage C - d'où le nom csh- surtout pour les expressions.
Branchement:
goto étiquette
L'exécution se poursuit par la ligne repérée par
étiquette: commande
Conditionnelles: Elles ont trois formes
La partie else est bien sûr facultative. Les expressions ressemblent à leurs homologues du langage C , avec en plus les possibilités shell. Leur valeur logique est 0 pour faux, non 0 pour vrai. En voici des exemples.
($a == $b) <--- a et b déjà définies et égales
($?a) <--- a est-elle définie ? 0 ou 1
($a == 11 || $c != "toto")
($term == 'sun' && `tty` == "/dev/console")
Les différents éléments d'une expression doivent être séparés par espace tabulation ou parenthèses.
Exemple: Dans l'exemple précédent, on ne sauvegarde une fortune que si elle est jugée drôle...
# Affichage et sauvegarde de fortunes ...
/usr/demo/games/fortune > t
cat t
echo "Drole? (y/n)"
set a = $<
if ($a == "y") then
echo "-----------------------------" >> mesFortunes
cat t >> mesFortunes
echo "-----------------------------" >> mesFortunes
endif
unalias rm
rm t
D'autres tests, très intéressants, se rapportent aux fichiers.
if ( -d référence) ...
teste si la référence donnée est un répertoire. D'autres spécifications sont possibles:
-f si fichier ordinaire.
-e existence de fichier
-o si propriétaire de fichier
-r si droit de lecture sur fichier (-w et -x pour les autres droits)
-z si taille nulle (existe mais vide)
Cas multiples:
Les tests à plusieurs cas sont semblables à ceux de C.
switch (mot)
case valeur :
suite de commandes
breaksw
case valeur :
suite de commandes
breaksw
...
default:
suite de commandes
endsw
Le branchement se fait vers le cas étiqueté par la valeur correspondante. Une commande facultative breaksw (ce n'est pas break) permet de quitter une alternative car, comme en C, l'exécution se poursuit en séquence sur les autres cas. L'étiquette default, si elle existe, correspond aux cas non prévus.
Itérations:
- foreach variable (liste de mots)
suite de commandes
end
- repeat entier commande
- while (expression)
suite de commandes
end
Dans le cas [1] la variable est rendue successivement égale à chaque mot de la liste, et la séquence de commandes avant end est exécutée. foreach et le end correspondant doivent être sur une ligne à part. Exemple:
foreach i (toto titi tutu)
echo $i
end
a pour effet d'imprimer les trois mots toto titi tutu. Noter l'usage $i de la variable i de contrôle, qui peut servir dans l'itération.
Le cas [2] répète entier fois la commande donnée, et le cas [3] répète la suite de commandes jusqu'à ce que l'expression devienne fausse.
Les commandes continue ou break, comme en C, s'utilisent à l'intérieur d'une boucle pour respectivement quitter l'itération courante (et passer à la suivante) ou quitter définitivement la boucle.
Les exceptions:
onintr étiquette
A la réception d'un signal (ou interruption) quelconque, le traitement se poursuit à l'étiquette donnée.
Un fichier commande peut être paramétré. Les arguments, paramètres effectifs, sont tapés sur la ligne commande correspondante après le nom du fichier. Dans le texte du script, les paramètres formels sont désignés par $i, où i est le i-iéme paramètre effectif dans l'ordre de présentation de la ligne commande. Par convention $0 est le 0-ième paramètre qui est le nom de la commande. Exemple:
% cat essai
#
echo $1 $2 $3
echo $0
% essai a b c
a b c
essai
%
S'il manque des paramètres sur la ligne commande, seuls ceux fournis seront utilisés. S'il y en a trop, ils seront ignorés.
% essai a b
a b
essai
% essai a b c d e
a b c
essai
%
Il y a un autre moyen de désigner les paramètres formels. C'est la variable tableau prédéfinie argv (comme en C).
% cat essai
#
echo $argv[1] $argv[2] $argv[3]
% essai a b c
a b c
% essai a b
Subscript out of range.
argv[0] n'est pas défini! Il y parfois erreur de débordement de tableau de l'autre côté (argv[3] dans l'exemple).
Noter que dans la première notation, $* signifie tous les arguments, correspondant à $argv (sans indexation) dans la seconde. Par ailleurs, $#argv est nombre des paramètres passés.
Voici un programme qui cherche le rang de l'argument toto dans la liste de ceux passés à la commande.
% cat indice
#
set n=1
while ($n <= $#argv)
if ($argv[$n] == "toto") then
echo trouve $n
break
else @ n++
endif
end
if ($n > $#argv) echo "non trouve"% indice a b toto c d
trouve 3% indice a b c
non trouve
Voici pour terminer, un exemple complet. C'est une procédure cataloguée qui enlève les fichiers exécutables et/ou objets dont le source existe. Elle se base sur le fait qu'ils ont le mêmes nom de base, i.e. si toto.c existe ainsi que toto et toto.o, ces deux derniers sont supprimés. C'est parfois utile pour économiser l'espace disque (s'il n'y a pas d'application qui est supposée les utiliser directement).
#! /bin/csh
# Procedure qui efface les fichiers F ou F.o correspondant a`
# un fichier F.c (si ils existent)
#
# USAGE: net [dir]
# si ce fichier s'appelle "net" pour nettoyer le directory
# donné (defaut directoty courant)
#
if ( $#argv > 0) then
cd $1
endif
#
# Pour plus de securite decommenter de la ligne suivante
# alias rm "rm -i"
#
# Supprimer fichiers executables
#
echo "Supprimer executables?(y/n)"
set a=$<
if ($a == "y")then
foreach f (`ls *.c`)
#teste si des fichiers executables existent et les enleve
set file=`basename $f .c`
if ((-e $file) && !(-d $file)) then
rm $file
endif
end
endif
#
# Supprimer fichiers objets
#
echo "Supprimer objects?(y/n)"
set a=$<
if ($a == "y")then
foreach f (`ls *.c`)
# teste si des fichiers objets existent et les enleve
set file=`basename $f .c`
if ((-e ${file}.o) && !(-d ${file}.o)) then
rm $file.o
endif
end
endif
PRECEDENT | SOMMAIRE | SUIVANT |