Acte VI - IV : Les scripts Shell.
Les tests en Shell:
En Shell les programmes ont tous une valeur de retour permettant d'indiquer si tout s'est bien passé ou si une erreur est survenue. La valeur de retour 0 indique que le programme s'est bien déroulé, toute autre valeur correspond à un code d'erreur. La valeur de retour de la dernière commande exécutée est stockée dans une variable nommée ? Exemple:
$ echo fichier de test >> fic1 # on a créé un fichier fic1
$ chmod 000 fic1 # on supprime les droits sur ce fichier
$ cat fic1 # on essaye d'afficher son contenu -> ERREUR
$ echo $? # affiche 1 (différent de 0)
$ chmod u+r fic1 # on remet le droit de lecture
$ cat fic1 # Affiche le contenu de fic1
$ echo $? #Affiche 0: la commande cat s'est bien déroulée.
Nous avons vu qu'il est possible en shell de créer des variables. il existe une commande permettant d'effectuer des tests sur les entiers ou les chaînes de caractères: « test ».
Si vous consultez le man de test vous trouverez tous les opérateurs de comparaison.
La commande test renvoie 0 si le test demandé est validé et 1 sinon. Par exemple:
$ test 1 -eq 2; echo $? # Affiche 1
$ test 1 -eq 1; echo $? # Affiche 0
Un raccourci pour la commande test est []. Les 2 commandes sont équivalentes: « test 1 -eq 2 » et « [ 1 -eq 2 ] » (attention ne pas oublier les espaces).
On peut utiliser des opérateurs booléen (manipulant les valeurs Vrai et Faux (0 et différent de 0)) sur une ligne de commande shell. Voici ces opérateurs:
&& : et : exemple: « expr1 && expr2 » expr2 n'est exécuté que si expr1 renvoie 0 (VRAI)
|| : ou : exemple : « expr1 || expr2 » expr2 n'est exécuté que si expr1 renvoie 1 (FAUX).
Voici un exemple complet de l'utilisation des opérateurs et de la commande test:
$ test `ps | wc -l` -gt 10 && echo Plus de 10 processus lancés.
Le fait de mettre une commande entre ` fait qu'on l'exécute. Le shell va donc commencer par exécuter la commande « ps | wc -l » ce qui a pour effet de compter le nombre de processus. Puis ce nombre va être l'argument dans la commande test: « test nb_proc -gt 10 »: ici la valeur de retour va être 0 (Vrai) si le nombre de processus est supérieur à 10 et 1 (Faux) sinon. La commande echo ne sera exécutée que si le test a retourné Vrai. Donc toute cette commande n'affichera « Plus de 10 processus lancés » que si l'on a plus de 10 processus qui tournent sur le système.
Si l'on veut en plus afficher un message dans le cas où il y a moins de 10 processus lancés il faut rajouter une commande echo de la manière suivante:
$ test `ps | wc -l` -gt 10 && echo Plus de 10 processus lancés.|| echo Moins de 10 processus lancés
En effet l'évaluation de la valeur de l'expression se fait de gauche à droite donc:
Si le test échoue alors (test && echo) vaut Faux et donc la deuxième commande echo est lancée.
Si le test échoue alors (test && echo) vaut Vrai et donc la deuxième commande echo n'est pas lancée.
Exercices:
Donnez une commande affichant le message « more than 5 word »ou « less than 5 word » suivant que le fichier utilisé dans la commande a plus ou moins de 5 mots.
Donnez une commande shell utilisant la commande date et indiquant si on est l'après-midi ou le matin.
if...then...else:
Une manière plus simple de faire une action selon un test est le « if..then..else ». Sa syntaxe est la suivante:
if [TEST] ; # Si la valeur de TEST est vrai
then [INSTRUCTIONS] ; # Alors on fait les INSTRUCTIONS de then
else [INSTRUCTIONS] ; #Sinon on fait les INSTRUCTIONS du else.
fi; # Indique la fin du if.
Exemple:
$ i=`ps | wc -l`
$ if [ $i -gt 10 ] # ou if test $i -gt 10
>then echo You run more than 10 process.
>else echo You run less than 10 process.
>fi;
Remarques:
Dans le shell il revient au même de mettre des « ; » entre le if then else ou de passer à la ligne entre chaque instruction. (le ; code un retour chariot).
le else est optionnel.
Les boucles:
Boucle for:
La boucle for permet de faire des itérations d'un bloc d'instruction autant de fois que d'éléments dans une liste.
Syntaxe: for variable in liste ; do [INSTRUCTIONS] ; done;
variable va prendre successivement la valeur de chaque élément dans la liste et pour chaque valeur, le bloc INSTRUCTIONS va être exécuté.
Boucle while:
La boucle while permet d'exécuter un bloc d'instructions tant qu'une condition est Vrai.
Syntaxe: while commande; do instructions; done;
Tant que le test commande est validé, le bloc instructions va être exécuté.
Boucle until:
De même que la boucle while mais cette fois les instructions seront exécutées tant que la condition du until n'est pas remplie.
until commande; do instructions; done;
L'aiguillage:
L'instruction case permet d'exécuter un bloc d'instructions en fonction de la valeur d'une variable.
Syntaxe:
case $variable in
motif1) instructions 1 ;;
motif2) instructions 2 ;;
*) instructions par defaut ;;
esac
Le bloc correspondant au motif * n'est exécuté que si aucun motif précédent ne correspond à la valeur $variable.
Les ruptures:
On peut interrompre une boucle (for while until) dans les instructions de celle-ci de différentes façons.
continue nb_boucle : retour au début de la boucle (for while until), nb_boucle correspond au niveau de boucle à partir de la boucle la plus externe
break nb_boucle : permet de sortir de la boucle. nb_boucle correspond au niveau de boucle à partir de la boucle la plus externe
Les scripts:
Les scripts permettent de faire un succession de commandes de manière organisée. Les instructions sont dans un fichier. Celui-ci a le format suivant:
#!/bin/bash # défini la référence absolue sur l'interpréteur de commandes (ici bash).
...
instructions
...
Pour la première ligne, il existe d'autres façons de procéder:
la ligne #!/bin/bash indique l'interpréteur à utiliser. Alors on donne les droit d'exécution au script (u+x) et on l'exécute. Le shell va alors lancer l'interpréteur qui lui va exécuter les instructions.
Si votre interpréteur courant est déjà la bash. On peut se passer de la première ligne. C'est déconseillé car dans ce cas votre script ne fonctionnera que sous bash. (note: il faut mettre aussi le droit d'exécution).
Sinon on peut soit même lancer l'interpréteur et lui donner le scripte en argument. (pas besoin des droits d'exécution).
Dans un script on peut: déclarer des variables, faire des boucles, .... En plus des instructions de rupture décrites plus haut on a l'instruction exit n qui a pour effet de mettre fin à l'exécution du script qui aura comme valeur de retour n. (echo $?).
De plus, dans un script il existe des variables prédéfinies:
$0 nom du script (pathname)
$1, ..., $9 arguments (du 1er au 9ème)
$# nombre d'arguments
$* liste de tous les arguments
$@ liste de tous les arguments
$? code retourné par la dernière commande
$$ numéro de processus de ce shell
$! numéro du dernier processus en arrière plan
$- drapeaux fournis au shell par set