guill.net - La page des réseaux
 

Programmation Unix : les scripts
Merci à l'auteur : Daniel Schang

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.

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...) :
 
 

Nom Descriptif
HOME Nom du répertoire courant de l'utilisateur
LOGNAME Nom de connexion de l'utilisateur
PATH Liste des répertoires explorés par le système pour rechercher une commande
PS1 Prompt d'invitation à entrer une commande
SHELL Nom du shell utilisé
TERM Nom 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.
Expression Vraie si
-a ref ref existe
-d ref ref est un répertoire
-f ref ref est un fichier
-s ref ref existe et est de taille non nulle
-n chaine chaine est de longueur non nulle
-z chaine chaine est de longueur nulle
num1 -eq num2 égalité numérique (equal)
num1 -ne num2 inégalité numérique (non equal)
num1 -gt num2 supérieur numérique (greater than)
num1 -ge num2 supérieur ou égal numérique
num1 -lt num2 inférieur numérique
num1 -le num2 inférieur ou égal numérique
chaine1 = chaine2 égalité alphanumérique
chaine1 != chaine2 inégalité alphanuméerique
chaine1 > chaine2 supérieur alphanumérique
chaine1 < chaine2 infé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.
Solution

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...
Solution

Règle 1

Chaque commande possède par défaut:

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 >.
Solution

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:
 
nature opérateur(s)
opérateurs arithmétiques + - * / % ^ (puissance)
opérateurs d'incrémentation ++ -
opérateurs relationnels == != < > <= >=
opérateurs d'affectation = =+ =- =* =/ =%
calcul de la racine carrée sqrt

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.
Solution

Interpréter tout le fichier en le passant à bc.
Solution

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...
Solution

La structure de contrôle for/do

La structure de cette commande est la suivante:

for variableinmot1 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
Solution

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.
Solution

Le script de la factorielle

Ecrire un script shell factorielle <n> qui calcule la factorielle du nombre n.
Solution

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.
Solution

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:


Suite