Comment ecrire un script Shell


Introduction au shell basée sur le cours
An Introduction to Shell Programing par
Reg Quinton <REGGERS@JULIAN.UWO.CA>

Introduction

Un shell est un interpreteur de lignes de commande. Il recoit les commandes et les execute. Cela peut s'apparenter a un langage de programmation. Le Bourne shell (ndt:bsh) est utilise pour creer des scripts shell -- en d'autres termes, des programmes interpretes/executes par le shell. Vous pouvez ecrire des scripts shell avec du C-shell; pour des raisons de longueur, nous ne le traiterons pas ici.

 

Creation d'un script

Supposez que vous utilisez souvent la commande 

    find . -name file -print

et que vous prefereriez taper une commande simple telle que

    sfind file

Creez un script shell

    % cd ~/bin
    % emacs sfind
    % page sfind
    find . -name $1 -print
    % chmod a+x sfind
    % rehash
    % cd /usr/local/bin
    % sfind tcsh
    ./shells/tcsh

Observations

Ce rapide exemple est loin d'etre tres adequate mais permet les observations suivantes:

  1. Les scripts shell sont de simples fichiers texte cree avec un editeur
  2. Les scripts shell ont le droit d'execution (ndt:x)
  3.     %chmod a+x sfind
        
  4. Ils doivent etre situes dans votre chemin de recherche et votre ~/bin doit aussi etre dans votre chemin de recherche
  5. Vous aurez surement besoin de faire des modifs si vous utilisez un autre shell que celui sous lequel vous avez fait votre script
  6. Les arguments sont passes en ligne de commande et son references. Par exemple, $1 est une variable

 

#!/bin/sh

Tous les scripts Bourne Shell doivent commencer par la sequence

    #!/bin/sh

Exemple tire de la page du manuel de la commande exec (2):

"Sur la premiere ligne de l'interpreteur de script suivant le "#!" devra figurer le nom du programme qui doit etre utilise pour interprete le contenu du fichier. Par exemple, si la premiere ligne contient "#! /bin/sh", le contenu du fichier sera alors execute comme un script shell."

Vous pouvez passer outre cet formalite, mais vous ne devriez pas. Tous les bon scripts etablissent explicitement quel interpreteur doit etre utilise. Il y a longtemps, il y avait uniquement un seul interpreteur (Le Bourne Shell) mais aujourd'hui, il y a beaucoup plus d'interpreteurs -- Csh, Ksh, Bash, et bien d'autres.

Commentaires

Les commentaires sont precedes du caractere diese (#). Un commentaire peut commencer n'importe ou sur une ligne et continue jusqu'a le fin de la ligne.

 

Chemin de recherche

Tous les scripts shell devraient inclure un chemin de recherche specifique:

    PATH=/usr/ucb:/usr/bin:/bin; export PATH
    PATH=/usr/ucb:/usr/bin:/bin; export PATH
Une specification du PATH est recommandee -- Dans bien des cas le script ne fonctionnera pas chez differents utilisateurs car le chemin de recherche est manquant ou incomplet.

Le Bourne Shell n'exporte pas les variables d'environnement a son heritage a moins que vous l'ayez explicitement declare en utilisant la commande export.

La verification des arguments

Un bon script shell doit verifier que les arguments passes (s'il y en a) sont corrects

    if [ $# -ne 3 ]; then
echo 1>&2 Usage: $0 19 Oct 91
exit 127
fi

 

Ce script necessite trois arguments et averti en cas de probleme.

Exit status

Toutes les applications Unix doivent retourner un status de sortie (ndt: Pas forcement, si vous proggez a la porc, y'en a pas besoin..Enjoy :)

    # is the year out of range for me?

if [ $year -lt 1901 -o $year -gt 2099 ]; then
echo 1>&2 Year \"$year\" out of range
exit 127
fi

etc...

# All done, exit ok

exit 0

Un status de sortie different de zero indique une condition d'erreur alors qu'un status a zero indique le script s'est execute correctement.

Sur les systemes BSD, il y a un classement en categorie des codes de sorties les plus souvent usites. Voir /usr/include/sysexits.h

Utiliser le status de sortie (exit status)

les codes de sorties sont important pour la plupart des gens qui utilisent votre code. Beaucoup construisent des tests sur le status de sortie d'une commande.

La condition de construction est:

    if command; then
command
fi

Par exemple,

    if tty -s; then
echo Enter text end with \^D
fi

Votre code devrait etre ecrit dans la vision que d'autres pourront l'utiliser. Assurez vous que vous retournez un code de sortie significatif. Cela les aidera beaucoup.

Stdin, Stdout, Stderr

Entree standard, sortie standard et la sortie d'erreur sont les descripteurs de fichier 0, 1 et 2. Chacun a un role particulier et doit etre utilise a propos.

    # is the year out of range for me?

if [ $year -lt 1901 -o $year -gt 2099 ]; then
echo 1>&2 Year \"$year\" out of my range
exit 127
fi

etc...

# ok, you have the number of days since Jan 1, ...

case `expr $days % 7` in
0)
echo Mon;;
1)
echo Tue;;

etc...

Le message d'erreur doit apparaitre sur stderr et pas sur stdout! Les sorties doivent apparaitre sur stdout. Comme pour le dialogue input/outpout:

    # give the fellow a chance to quit

if tty -s ; then
echo This will remove all files in $* since ...
echo $n Ok to procede? $c; read ans
case "$ans" in
n*|N*)
echo File purge abandoned;
exit 0 ;;
esac
RM="rm -rfi"
else
RM="rm -rf"
fi

Note: Ce code se comporte differement s'il doit communiquer avec un utilisateur. (Si l'entree standard est un tty plutot qu'un pipe, ou un fichier, ou etc. Voir tty(1)).

Les structures de controle

Quelques astuces