Les principales commandes de shell sous UNIX

Introduction

Un "shell" est un interpréteur de commandes du système UNIX. Il existe plusieurs versions de cet interpréteur : le "shell de Bourne" sh (ou "Bourne shell"), le "Korn shell" ksh, le "C_shell" csh, et d'autres encore comme bash trés utilisé sous système Linux.
On se placera dans le cadre du shell de Bourne.
Le format d'une commande sous UNIX suit le modèle suivant :

nom_de_la_commande -options arguments

Les options et arguments forment ce que l'on appelle les "paramètres" de la commande.

Nous ne reviendrons pas sur la définition des métacaractères de shell, des expressions régulières et des redirections d'entrée, de sortie et d'erreur supposées être connues à l'issue du rappel des principales commandes Unix.

Les "scripts"

Un "script" est un ensemble de commandes UNIX rassemblées dans un fichier. Pour lancer l'exécution d'un script contenu dans le fichier nom_script, on peut :

Les paramètres positionnels

$0, $1, $2, $3, $4, $5, $6, $7, $8 et $9 désignent les paramètres positionnels, à l'appel d'un script. $0 désigne le nom du script. On désigne également par $# le nombre total de paramètres positionnels ($0 non compris), et par $* la liste des paramètres positionnels. Enfin, $? contient le code de retour de la dernière commande exécutée.

Exemple :

On écrit, dans le fichier exemple.sh, les commandes suivantes :

exemple.sh
echo "exécution de la commande $0"
echo "contenu du fichier 1"
cat $1
echo "contenu du fichier 2"
cat $2

On rend ce script exécutable en tapant, dans le répertoire de travail :

tgv% chmod u+x exemple.sh

Puis on l'exécute, en tapant :

tgv% exemple.sh fich1 fich2

Les opérateurs && et ||

La structure de contrôle de condition

Dans un "script", il est possible de structurer les commandes en effectuant des appels conditionnels.

Syntaxe :

if condition1
then
liste_commandes_1


elif condition2
then
liste_commandes_2


else
liste_commandes_3
fi

Remarques :

Exemple :

if [ $# -eq 1 ]
then
echo "Le répertoire $1 a le contenu suivant : `ls $1`"
else
echo 'Mauvais nombre de paramètres'
fi

Ce "script" affiche le contenu du répertoire donné en paramètre. S'il n'y a pas exactement un paramètre, un message est affiché.

La structure de contrôle d'aiguillage à choix multiple

Cette structure de contrôle permet d'effectuer un branchement conditionnel sur une séquence de commandes, en fonction de la valeur d'une variable.

Syntaxe :

case variable in
cas1)
liste_commandes_1
;;

cas2)
liste_commandes_2
;;

cas3|cas4)
liste_commandes_3
;;
*)

liste_commandes_4
;;
esac
Dans ce modèle :

Exemple

case $# in
0)
set variable=`pwd`
;;
1)
set variable=$1
;;
*)
echo "Erreur de syntaxe" ; exit
;;
esac

Dans ce "script", la variable variable reçoit comme valeur le répertoire courant (si le nombre de paramètres est nul) ou la valeur du paramètre positionnel $1 (s'il n'y a qu'un paramètre). S'il y a plus d'un paramètre, un message est affiché.

Remarque :

La commande break (équivalente à l'instruction break du langage C) existe, mais elle n'est pas nécessaire dans la structure de contrôle d'aiguillage à choix multiple, car le double point-virgule ;; est équivalent à cette commande.

La structure de contrôle "boucle For"

Cette structure de contrôle permet de lancer une séquence de commandes en boucle.

Syntaxe :

for variable in liste_de_cas
do
liste_commandes
done

Dans ce modèle, liste_de_cas est une liste de chaînes de caractères, utilisant éventuellement les métacaractères du shell.

Exemple :

for fichier in `ls *.c`
do
chmod go-r $fichier
done

Cette séquence change les droits d'accès de tous les fichiers du répertoire courant comprenant l'extension .c

Remarques :

- Dans les structures de contrôle de boucles, la commande break peut être utilisée.

- La syntaxe suivante :

for i
do
...


est équivalente à :

for i in $*
do
...

La structure de contrôle "boucle While"

Cette structure de contrôle permet d'exécuter une séquence de commandes en boucle tant qu'une condition est vérifiée.

Syntaxe :

while condition
do
liste_commandes
done

La structure de contrôle "boucle Until"

Cette structure de contrôle permet de boucler sur une séquence de commandes jusqu'à ce qu'une condition devienne vraie.

Syntaxe :

until condition
do
liste_commandes
done

Les variables du shell

Tout shell permet de gérer des variables non typées. Le nom d'une variable peut comporter des lettres, des chiffres et le caractère _ et le premier caractère ne peut pas être un chiffre.
Avec le shell de Bourne, l'initialisation d'une variable s'effectue à l'aide de la commande d'affectation, pour laquelle l'opérateur = est utilisé, comme en langage C :

x=7

Attention : il ne doit pas y avoir d'espace ni avant ni après l'opérateur =
Une variable peut recevoir comme valeur :

En fait, la seule "combinaison" que l'on peut faire directement est la concaténation de plusieurs valeurs. Toute autre opération doit être faite à l'aide de la commande expr, qui sera vue plus loin.
Pour faire référence à la valeur d'une variable du shell, il faut faire précéder son nom du métacaractère $

Remarques :
- Il existe, dans tout shell, un certain nombre de variables prédéfinies. Dans un shell de Bourne, sur tgv, il y en a 22, dont les noms ne comportent que des lettres majuscules, des chiffres et le caractère _
- Il ne faut pas confondre les variables d'un shell avec ses paramètres positionnels. Pour modifier la valeur d'un paramètre positionnel, il faut utiliser la commande set.

Exemple :

x=7
y=`pwd`
x=$y$x
echo $x


Si le répertoire de travail est /home/mod4g0 alors la commande echo produira l'affichage suivant :

/home/mod4g07

Lancement d'un "shell fils"

Une séquence de commandes placée entre parenthèses est exécutée par un "sous-shell" ou "shell fils". Tout déplacement dans l'arborescence des répertoires et toute modification de la valeur d'une variable dans un shell fils ne sont plus effectifs dès le retour dans le shell père.

Exemple :

$ cd
$ pwd
/home/mod4g0
$ a=1
$ (cd /usr/include; a=2; echo $a; pwd)
2
/usr/include
$ pwd
/home/mod4g0
$ echo $a
1

Remarques :
- L'entrée et la sortie standard d'un shell fils peuvent être redirigées au moment de l'appel. Ceci redirige alors implicitement toutes les entrées et sorties standard des commandes appelées dans le shell fils.
- Une variable x du shell père ne sera connue dans un shell fils qu'après lancement de la commande export x, mais les modifications de la valeur de x effectuées dans le shell fils ne seront pas répercutées dans le shell père.

Les fonctions en shell

En shell, on appelle "fonction" une séquence de commandes repérable par un nom qui est le nom de la fonction. Les commandes constituant une fonction sont exécutées dans le cadre du shell courant, et non dans le cadre d'un shell fils, comme c'est le cas pour un script ou pour une séquence de commandes placées entre parenthèses.

Syntaxe de la déclaration d'une fonction :

nom()
{
commandes
}

Une fonction doit être déclarée avant d'être appelée. Pour appeler une fonction, il suffit d'utiliser son nom, sans les parenthèses. Comme pour un script shell, l'appel d'une fonction peut être éventuellement suivi d'une liste d'arguments, accessibles dans la fonction à l'aide des paramètres positionnels $1, $2, ..., $9 (les paramètres $# et $* sont également initialisés).

Une fonction se termine soit après exécution de la dernière commande située avant l'accolade fermante, auquel cas le code de retour est celui de cette dernière commande, soit après exécution d'une commande return [n], auquel cas le code de retour est l'argument n de la commande return (ou 0 si cet argument est absent). Dans les deux cas, le code de retour de la fonction est affecté au paramètre $? du shell courant.

Attention : la commande return ne peut être utilisée qu'à l'intérieur d'une fonction (remarquer l'analogie avec la fonction return du langage C).

La commande set

Cette commande permet d'affecter des valeurs aux paramètres positionnels $1, $2, $3, ..., $9. Appelée sans paramètres, elle permet aussi d'afficher les valeurs de toutes les variables du shell courant :

Cette commande est très différente entre shell de Bourne, Korn shell et C_shell. On rappelle que c'est le shell de Bourne qui est présenté ici.

Syntaxe :

set [-aefhkntuvx] [valeur1] [...]

Options :

cf. la description de la commande set, en tapant : man set

Exemple 1 :

set alpha beta

Cette commande affecte la valeur alpha au paramètre positionnel $1, et la valeur beta au paramètre positionnel $2

Exemple 2 :

x=1
set


produira l'affichage suivant :

DISPLAY=141.115.12.137:0
GUIDEHOME=/usr/openwin/devguide
HOME=/home/mod4g0
...
x=1


Codes d'erreur retournés :

cf. la description de la commande set, en tapant : man set

La commande shift

Elle permet de décaler les arguments passés à l'appel d'un script d'un rang ou de n rangs vers la droite.

Syntaxe :

shift [n]

Options :

néant.

Exemple :

Soit le script :

deca.sh
echo "\nAvant décalage : $1 $2 $3 $4 $5 $6 $7 $8 $9"
shift
echo "Après décalage : $1 $2 $3 $4 $5 $6 $7 $8 $9\n"

Voici deux exemples d'exécution de ce script, avec des nombres d'arguments différents :


$ deca.sh 10 9 8 7 6 5 4 3 2 1

Avant décalage : 10 9 8 7 6 5 4 3 2
Après décalage : 9 8 7 6 5 4 3 2 1

$ deca.sh 5 4 3 2 1

Avant décalage : 5 4 3 2 1
Après décalage : 4 3 2 1

Donc $1 reçoit la valeur de $2, $2 reçoit la valeur de $3, etc...

Codes d'erreur retournés :

Remarques :

- Lors de l'appel de la commande shift, l'absence d'argument n équivaut à une valeur de cet argument égale à 1.
- La valeur de $# est mise à jour par la commande shift.

La commande test

Elle permet d'effectuer des tests de comparaison, en renvoyant la valeur 0 lorsque la comparaison est vraie, et une autre valeur sinon. Cette commande est surtout utile en complément aux structures de contrôle, comme la structure de contrôle de condition qui sera vue dans le paragraphe suivant.

Syntaxe 1 :

test comparaison

ou :

[ comparaison ] (bien respecter les espaces dans ce cas !)

La comparaison comparaison peut être la combinaison booléenne de plusieurs comparaisons élémentaires :

Des parenthèses précédées de caractères \ (les parenthèses étant des métacaractères du shell) peuvent être nécessaires en cas combinaisons un peu plus compliquées, pour préciser les priorités, comme dans l'exemple suivant :

! \( comparaison1 -o comparaison2 \)

Chaque comparaison élémentaire doit être écrite avec la syntaxe suivante :

v1 comparateur v2

v1 et v2 sont des expressions du shell courant.

Le comparateur comparateur ne s'écrit pas comme en C. Si v1 et v2 sont entières :

Si v1 et v2 sont des chaînes de caractères :

Remarque :

Pour tester si la variable chaine a comme valeur la chaîne vide, on ne peut pas écrire test $chaine = "" car, si cette chaîne est vraiment vide, après évaluation des métacaractères, cette commande sera évaluée sous la forme test = "", qui est incorrecte. Cela justifie l'introduction de la deuxième syntaxe suivante pour la commande test :

Syntaxe 2 :

test chaine

Dans cette écriture, la commande test teste si chaine est une chaîne vide. Il existe une troisième syntaxe pour la commande test :

Syntaxe 3 :

test -fdrwx nom ...

Options :

Exemple 1 :

test $1 -gt 0 -a $# -eq 2

Exemple 2 :

test $chaine

Exemple 3 :

test -d /home/mod4g0/TD

Codes d'erreur retournés :


Ces pages ont été adaptées à partir de celles réalisées par J.D. Durou et Ph. Joly avec leur aimable autorisation.