Programmation Unix : les scripts  
 

 

De la compréhension des scripts

A partir des commandes shell, chaque utilisateur peut créer ses propres fichiers de commandes appelés scripts.

Variables et substitution

Les chaînes peuvent être délimitées par les trois caractères ', " et `. Ces délimiteurs se différencient par le type de substitions qui sont réalisées à l'intérieur des chaînes qu'ils délimitent.

    le caractère '(simple quote) : tous les caractères à l'intérieur d'une chaîne délimitée par ce caractère sont considérés comme protégés, c'est-à-dire perdent, s'ils en ont un, leur aspect spécial. Le seul caractère qui ne peut appartenir à une chaîne ainsi délimitée est le caractère ' lui même. Plus aucune substitution n'a donc lieu dans une chaîne délimitée par ce caractère;

    le caractère "(double quote) : à l'intérieur d'une telle chaîne, les caractères $ anti-slash ' ` sont encore des caractères spéciaux. Cela signifie que la substitution des variables (rôle du caractère $) est réalisée et l'évaluation des commandes également (rôle du caractère `). Une chaîne ainsi délimitée peut contenir le caractère ": il suffit en effet de la faire précéder du caractère \ pour indiquer qu'il ne doit pas être interprété comme délimiteur.

    le caractère `(anti quote) : une chaîne délimitée par ce caractère est interprétée comme une commande (après réalisation des substitutions des valeurs aux variables) et le résultat de la commande lui est substitué.

Les commandes suivantes vous permettront de bien appréhender le rôle du caractère spécial ` pour la substitution et la manipulation des variables shell.

$ a=schmilblick
$ echo $a
$ echo a
$ echo pwd
$ echo `pwd`
$ dir=pwd
$ echo dir
$ echo $dir
$ dir=`pwd`
$ echo $dir

Affichage des principales variables d'environnement

Afficher le contenu des variables réservées du shell suivantes (attention aux majuscules...):

NomDescriptif
HOMENom du répertoire courant de l'utilisateur
LOGNAMENom de connexion de l'utilisateur
PATHListe des répertoires explorés par le système pour rechercher une commande
PS1Prompt d'invitation à entrer une commande
SHELLNom du shell utilisé
TERMNom du terminal

Redéfinissez votre prompt de la manière que vous souhaitez.

Premier script simple

Taper l'exemple suivant dans le fichier dddate:

 date
 dddate

Rendre le fichier  dddate executable...

Lancer ensuite la commande dddate. Pour stopper un programme qui boucle, il suffit de presser simultanément sur les touches <CTRL> et <C>.

Les paramètres des scripts

La variable de nom * (interrogeable avec echo $* par exemple !) est interne au shell et a pour valeur la liste des variables de position, c'est à dire des paramètres transmis lors d'un appel à un fichier de commandes (ou script). Chacun de ces paramètres peut être désigné par sa position dans la liste : les valeurs de ces paramètres étant : $1, $2, etc. De plus, $0 est le nom de la commande exécutée. Enfin, le nombre de paramètres est donné par la valeur $# de la variable #.
Taper le script com_bash1 suivant :

echo la commande a $# paramètres
echo liste des paramètres: $*
echo nom de la commande : $0
echo paramètre 1 : $1
echo paramètre 13 : $13

Puis entrer:

$ ls -l com_ksh1
r w x r - x - - -    1    schang   ens      115   Nov   10 : 07  com_ksh1
$ com_ksh1 a b c d e f g h i j k l m n o
la commande a 15 paramètres
liste des paramètres : a b c d e f g h i j k l m n o
nom de la commande : com_ksh1
paramètre 1 : a
paramètre 13 : m

Quelques remarques et règles de programmation en shell

La structure de contrôle if/then/else

La structure de cette commande est la suivante:

if expression1
     then commande1
     else commande2
fi

!!! Attention, il est très important de placer un retour chariot entre les lignes if expression1 et      then commande1 par exemple.

A la limite, il vaut mieux trop de retours chariot que pas assez comme dans l'exemple suivant qui fonctionne bien:

if
expression1
     then
commande1
     else
commande2
fi

Le Korn Shell et le Bourne Again Shell tant de véritables langages, ils permettent d'effectuer des tests, des structures de contrôle portant sur des expressions conditionnelles. Ces expressions sont de la forme test expression. Le tableau suivant présente quelques types d'expressions.

ExpressionVraie si
-a refref existe
-d refref est un répertoire
-f refref est un fichier
-s refref existe et est de taille non nulle
-n chainechaine est de longueur non nulle
-z chainechaine est de longueur nulle
num1 -eq num2égalité numérique (equal)
num1 -ne num2inégalité numérique (non equal)
num1 -gt num2supérieur numérique (greater than)
num1 -ge num2supérieur ou égal numérique
num1 -lt num2inférieur numérique
num1 -le num2inférieur ou égal numérique
chaine1 = chaine2égalité alphanumérique
chaine1 != chaine2inégalité alphanuméerique
chaine1 > chaine2supérieur alphanumérique
chaine1 < chaine2inférieur alphanumérique

La commande test évalue une expression et positionne un code de retour à 0 si la condition est vraie et à 1 si la condition est fausse.

Utiliser la commande test afin d'écrire un script appelé what. Ce script teste si un nom est un répertoire ou non
Dans le cas où c'est est un répertoire, le contenu de ce dernier devra être listé. Si c'est un fichier, il faudra que le script indique la nature de ce fichier (utiliser la commande file <nom du fichier>).

Remarque 1

Les structures de contrôle conditionnelles utilisent le code de retour de la dernière commande exécutée.

Remarque 2

La variable shell ? (accessible par $? donc !) contient le code de retour de la dernière commande exécutée.

Essayer l'exemple suivant:

$ date
$ echo $?
$ ddddate
$ echo $?

Remarque 3

La commande exit n termine un script avec un code de retour égal à n (Si n n'est pas précisé, le code de retour du script est celui de la dernière commande exécutée).

Tester cette remarque à l'aide d'un petit script que vous inventerez.
Voir page des solutions

Remarque 4

La commande read lit une ligne sur l'entrée standard. Créer le script essai suivant:

read entree
echo $entree

Ecrire une commande équivalente (1 ligne!) à ces 2 lignes intitulée equiv, elle ne doit utiliser de read. Vous pourrez tester votre commande avec la phrase : equiv ok l'exemple fonctionne qui affichera alors à l'écran la chaîne ``ok l'exemple fonctionne''. Si vous ne trouvez pas au bout de quelques minutes voici la solution...
Voir page des solutions

Règle 1

Chaque commande possède par défaut:

    une entrée standard : le clavier,
    une sortie standard : l'écran,
    une sortie d'erreur: l'écran.

Règle 2

L'entrée et les sorties standard d'une commande peuvent être redirigées vers un fichier spécial ou ordinaire.

Symbole de la redirection en entrée: <
Symbole de la redirection en sortie: >

Exemple:

$ date > fichier
$ cat fichier

Le symbole >> permet d'ajouter quelque chose à un fichier déjà existant

Règle 3

Le symbole | (dénommé ``tube'' en français et ``pipe'' en anglais) permet de connecter la sortie standard d'une commande à l'entrée standard de la commande suivante. Exemple:

$ ls -l | wc -l

Imaginez un script (2 lignes suffisent!) permettant de réaliser exactement la même commande en utilisant les symboles de redirection < et >.
Voir page des solutions

Compteurs

Tapez le script compt suivant :

i=0
i=$i+1
echo $i
let i=0
let i=i+1
echo $i

Lancez le

Calculs mathématiques

Que fait la fonction factor ? Essayez avec factor 12 et factor 144... factor 149.

La primitive expr <argument> permet l'évaluation d'expressions mathématiques. Les différents termes de l'expression sont des arguments de la commande et en tant que tels doivent être séparés les uns des autres par un espace ou une tabulation (au moins). Il est possible par cette commande de manipuler des nombres entiers quelconques (les nombres négatifs sont reconnus).

Essayer par exemple:

$ expr 12 + 5
$ expr 12 / 5

{Si expr permet d'effectuer d'autres calculs, comme vous pouvez le voir, elle est cependant assez pauvre. Aussi, Korn-Shell et le Bash-shell proposent une commande bien plus puissante qui est bc. bc dispose entre autre des opérateurs suivants:
natureopérateur(s)
opérateurs arithmétiques+ - * / % ^ (puissance)
opérateurs d'incrémentation++ -
opérateurs relationnels== != < > <= >=
opérateurs d'affectation= =+ =- =* =/ =%
calcul de la racine carréesqrt

Tester cet interpréteur avec les commandes:

$ bc -l
4+5
x=4.5
y=3.2
x+y
sqrt(2)
etc...
quit
$

Avec un copier-coller (le coller se faisant avec le 3ème bouton de la souris) créer le fichier fonctions qui reprend ce que vous venez de taper ci-dessus sous bc.
Voir page des solutions

Interpréter tout le fichier en le passant à bc.
Voir page des solutions

La structure de contrôle while/do

La structure de cette commande est la suivante:

while expression
     do commande
done

1°) Créer un fichier texte essai quelconque de 5 lignes.
2°) Créer un script lecture qui va lire ce fichier et en afficher le contenu. L'appel au script se fera par:

$ cat essai | lecture

Une piste: utilisez la commande ``read'' qui lit normalement son entrée au clavier. Ici de toute façons, le script lecture sera trompé car son entrée est fournie par la sortie du fichier essai...
Voir page des solutions

La structure de contrôle for/do

La structure de cette commande est la suivante:

for variable in mot1 mot2 ...
     do commande
done

Observez la liste de commandes suivantes qui va nous servir pour le script ci-après:

$ i=1
$ echo $i
$ echo ${i} foo

Ecrire un script qui va créer dans votre répertoire shell les 10 fichiers suivants dont le contenu sera par exemple la date de création :
     #foo      $foo     &foo     (foo     -foo     ;foo     >foo     <foo      [foo     ]foo

Voir page des solutions

Un script simple

Ecrire un script shell récursif compte <n> en shell (donc pas en C) qui affiche les n premiers nombres dans l'ordre décroissant.
Voir page des solutions

Le script de la factorielle

Ecrire un script shell factorielle <n> qui calcule la factorielle du nombre n.
Voir page des solutions

Un peu de détente avant d'attaquer la suite...

Nous allons tester la commande at avec par exemple

$ at now + 1 minute
at> ls -l
at> CTRL+D

Au bout d'une minute, vous pourrez taper mail pour récupérer le résultat:

taper <RETURN> ou 1 pour voir le contenu du mail
taper d ou d 1 pour supprimer ce mail

On peut également essayer at now + 400 months...

Essayer les commandes suivantes:

$ tty           donne le nom complet de votre ligne de connexion.
$ who
$ w

Pour communiquer avec l'un de vos collègues utiliser la commande:

$ write <nom de login>
bonjour
CTRL+D

Pour recevoir (respectivement ne plus recevoir) de messages, il suffit de taper

$ mesg y
ou
$ mesg n

Le fait de taper mesg vous renvoie l'état de votre drapeau de communication.

La commande talk <login d'un collègue> fonctionne encore mieux (normalement... ?!?)

En cas de crise d'amnésie, pensez à taper l'une des trois commandes suivantes:

$ who am i
$ id
$ logname

Enfin la commande clear fait...

Un détour par un traitement de texte sous UNIX

Essayez l'éditeur de textes vi par:

$ vi essssai
taper quelque chose
pour sortir, il faut utiliser la séquence ``Esc'' + ``:wq'' (ne pas oublier le ``: '').
si on rappelle le fichier par vi essssai, on pourra passer en mode insertion en appuyant d'abord sur la touche ``i''. Pour supprimer une ligne, utiliser la séquence ``Esc + dd''...

La convivialité n'est pas au rendez-vous mais vi peut rendre certains services.

Un traitement de texte ?

Nous allons à présent créer un document sous LaTeX. Ce traitement de texte (gratuit) fait partie en standard d'une majorité de distributions LINUX.

    récupérer le document suivant et le sauvegarder dans votre répertoire sous le nom premier.tex.

    \documentclass[a4paper,french]{article}
    \usepackage[T1]{fontenc}
    \usepackage[latin1]{inputenc}
    \pagestyle{plain}
    \usepackage{babel}
    \usepackage{color}
    \makeatletter
    \newcommand{\LyX}{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\spacefactor1000}
    \makeatother
    \begin{document}
    {\centering {\LARGE BUREAU D'ETUDE PROGRAMMATION UNIX}\LARGE \par}
    {\centering \textbf{\small Durée:} 8 heures\par}
    {\centering \textbf {\small  G. Desgeorge et D. Schang}\par}
    \vspace*{1cm}
    {\centering -----------------------------------------------------\par}
    \textbf{\small Objectifs:} posséder les principales commandes UNIX ainsi que
    de bonnes bases en programmation UNIX.
    {\centering -----------------------------------------------------\par}
    \bigskip{}
    \vspace*{1cm}
    \tableofcontents
     
    \newpage
    %====================================================================
    \section{Introduction}
    %====================================================================
    Ce bureau d'études est consacré à l'utilisation et à la manipulation de
    \textit{shells} (sous UNIX, un \textit{shell} n'est rien d'autre qu'un interpéteur
    qui cherche à comprendre les commandes que vous entrez au clavier par exemple).
     
    Steve Bourne a donné son nom au premier shell utilisé sous UNIX, le Bourne-Shell:
    \textit{sh}. D'autres shells existent tels que le \textit{rsh} (Restricted Shell),
    le \textit{csh} (C-Shell, un shell dérivé du langage C), le \textit{bash} (Bourne
    Again Shell), le ksh (Korn-Shell). Ce sont ces deux derniers que nous étudierons
    plus précisément dans ce polycopié.
    \section{Les commandes usuelles}
     
    {\noindent Pour lancer un KORN SHELL taper la commande :}\\
    \textbf{/bin/ksh} ou \textbf{ksh}.\\
    {\noindent Pour lancer un BOURNE AGAIN SHELL taper la commande :}\\
    \textbf{/bin/bash} et \textbf{bash}.\\
    {\noindent Remarque: le BOURNE AGAIN SHELL est plus convivial sur vos machines,
    cela tombe bien, il est lancé par défaut sur vos machines au démarrage.}
     
    \subsection{Rappel de la liste des commandes usuelles}
     
    \vspace{0.3cm}
    {\centering \begin{tabular}{|l|l|}
    \hline
    Commande&
    Descriptif\\
    \hline
    \hline
    \textbf{ls}&
    affichage du contenu du répertoire\\
    \hline
    \textbf{mkdir}&
    création d'un répertoire (make directory)\\
    \hline
    \end{tabular}\par}
    \vspace{0.3cm}
    \end{document}

    jeter un oeil à son contenu (oui, il s'agit bien d'une partie du ``source'' de ce bureau d'études...)

    $ latex premier.tex    on compile le document!
    $ latex premier.tex    on recompile afin d'avoir une table des matières correcte
    $ xdvi premier.dvi
    $ dvips premier.dvi    crée le fichier postcript premier.ps
    $ kghostview premier.ps

La contre-partie à cette complexité du source du document se trouve dans le fait que LaTeX gère de manière très puissante les formules mathématiques. Enfin, des moulinettes autorisent des conversions faciles; essayez:

$ latex2html premier.tex
$ cd premier
$ ls -l
$ netscape premier.html

Autres scripts

L'argument est-il numérique ?

On se propose d'écrire un script numeric <paramètre> qui permet de tester si le paramètre qui lui est passé est numérique ou non. Idéalement, le script devrait fonctionner comme ceci:

$ numeric 12
Ok
numeric a
Err

Des idées pour l'écrire?!

Si vous avez quelques difficultés, voici une piste à suivre:

    L'idée est de faire un calcul mathématique avec l'argument qui a été passé (en utilisant expr par exemple). Bien entendu si ce n'est pas un nombre, une erreur se produira et la variable $? qui contient le code de retour de la dernière commande aura une valeur différente de 0.
    Il suffira donc de tester cette valeur et de renvoyer le bon message en conséquence.

    Un problème substiste cependant: la sortie standard est ``polluée'' par le résulat du calcul de expr, qu'il soit bon ou mauvais (par un message d'erreur dans ce dernier cas). La solution consiste alors à rediriger la sortie standard et la sortie en erreur de expr par expr ...... 1>/dev/null 2>/dev/null

    Ecrivez à présent le script complet.

Voir page des solutions

Le script carre

Ecrire un script carre qui calcule et affiche les carrés des nombres entiers compris entre m et n, ces derniers tant passés en paramètres du script.

Le script saison

Ecrire un script saison permettant de connaître la saison courante. Voici quelques pistes:

    regardez ce que renvoie la commande date
    utilisez la commande case,
    pour simplifier commencez par traiter une saison (l'été par exemple),
    enfin dernier détail, voici les dates de début des saisons:

      l'été commence le 21 juin,
      l'automne commence le 21 septembre,
      l'hiver commence le 21 décembre,
      le printemps commence en avance: le 20 mars.

Daniel Schang
 

-= From guill.net =-