Le Shell est à la fois un langage de commandes et l'interpréteur de ce langage.
Il assure l'interface externe entre les utilisateurs et le système, mais ne fait pas partie du noyau.
Principaux langages de commandes sont disponibles sur les systèmes UNIX :
![]() | le Bourne shell (sh), |
![]() | le C-shell (csh) basé sur sh, |
![]() | tcsh, basé sur csh, qui est du domaine public. |
.
.
L'interpreteur du shell a la possibilité, soit d'exécuter lui même la commande demandée par l'utilisateur (commande interne), soit de lancer l'exécution de programmes existant par ailleurs pour ce faire (commandes externes).
À chacune des commandes externes correspond un fichier exécutable ayant comme nom le nom de la commande. Ce fichier se trouve souvent dans le répertoires /bin
L'exécution d'une commande externe entraîne la création d'un nouveau processus exécutant le programme correspondant à la commande.
Une commande externe peut être appelée à partir de n'importe lequel des langages de commandes disponibles, mais aussi à partir d'un programme utilisateur.
Chacun des langages de commandes dispose de ses propres commandes qui sont les commandes internes.
Certains caractères jouent un rôle particulier :
![]() | * représente toute chaîne de caractères ; |
![]() | ? désigne un caractère quelconque (. dans l'éditeur ed) ; |
![]() | [...] désigne un caractère quelconque de l'ensemble spécifié dans .... Par exemple, [abc1] représente un caractère appartenant à {a, b, c, 1}. Des abréviations permettent de ne pas décrire explicitement tout l'ensemble : [0-9], [a-z], [A-Z] ; |
![]() | > et < représentent des redirections d'entrées/sorties standard ; |
![]() | | désigne un tube ; |
![]() | ; permet de construire une séquence ; |
![]() | <CR> passe à la ligne de commandes suivante. |
Si l'on désire utiliser ces caractères en tant que caractères normaux, il faut les faire précéder d'un caractère \ qui perd lui-même sa particularité lorsqu'il est doublé. Lorsqu'une référence de fichier commence par un ., ce premier caractère doit être spécifié explicitement car cette occurrence n'est pas couverte par la convention *.
Ces expressions permettent de désigner des ensembles de chaînes de caractères, en particulier dans des adressages et des substitutions. Elles peuvent donc être utilisées dans la plupart des commandes, à la place de chaînes de caractères.
Une expression rationnelle atomique est :
.
Les commandes du shell n'utilisent que des expressions rationnelles atomiques. Les autres peuvent être utilisées par exemple pour effectuer des substitutions de chaînes de caractères avec l'éditeur sed.
Une expression rationnelle est :
![]() | une expression rationnelle atomique ; |
![]() | une expression rationnelle atomique suivie du caractère d'itération * ; |
![]() | la concaténation d'expressions rationnelles ; |
![]() | une expression rationnelle atomique suivie de : |
![]() | \{n\} avec 0 ¾ n < 256 pour exactement n occurrences de l'express; |
![]() | \{n,\} pour au moins n occurrences de l'expression ; |
![]() | {m,n\} pour un nombre d'occurrences de l'expression entre m et n ; |
![]() | une expression comprise entre \( et \) pour délimiter des champs dans une ligne ; |
![]() | \n désignant le n-ième champ défini par le mécanisme précédent. |
La commande :
renvoie :
.
.
.
.
.
Lorsqu'un utilisateur se loge, un processus shell est exécuté. De plus, certaines commandes, soit communes, soit propres à chacun, sont effectuées :
![]() | .profile, |
![]() | .login |
![]() | .cshrc |
Ce type de commande permet l'initialisation de variables shell, soit pour leur donner une valeur différente de celle par défaut, soit pour en définir de nouvelles.
L'ensemble de ces variables constitue l'environnement shell.
Le nom d'une variable shell est une chaîne de caractères contenant des lettres, des chiffres ou le caractère _ et commençant toujours par une lettre.
La valeur d'une variable est une chaîne de caractères quelconque.
Une affectation de la valeur val à la variable var s'effectue par :
La valeur d'une variable var est obtenue en utilisant $var. Si la variable var n'a pas été définie, son contenu est la chaîne de caractères vide.
* '...' : ... est pris tel quel, c'est-à-dire que si cette chaîne contient des appels à des variables, aucune substitution n'est effectuée ;
* "..." : les variables contenues dans ... sont substituées ;
* 'op' : évalue la commande shell op.
La commande echo permet d'afficher une chaîne de caractères. L'option -n évite le retour à la ligne après affichage de la chaîne de caractères.
.
.
.
.
Une procédure (ou script shell ) est une suite de commandes shell. Elle peut accepter des paramètres:
commande paramètre1 ... paramètren.
Le premier paramètre est référencé par $1, le second par $2, ..., le neuvième par $9.
![]() | $1, $2, ..., $9 : paramètres de la commande ; |
![]() | $0 : nom de la commande appelée ; |
![]() | $* : liste des paramètres ; |
![]() | $# : nombre de paramètres ; |
![]() | $$ : numéro du processus shell correspondant à la commande ; |
![]() | $? : code de retour de la dernière commande exécutée. |
Les variables utilisées dans une commande sont locales à celle-ci.
.
.
.
.
Tests sur les chaînes de caractères
[ <chaîne de caractères 1> = <chaîne de caractères 2> ]
Autres tests sur les chaînes de caractères
.
![]() | -eq (égales), |
![]() | -ne (différentes), |
![]() | -gt (strictement supérieure), |
![]() | -ge (supérieure ou égale), |
![]() | -lt (strictement inférieure), |
![]() | -le (inférieure ou égale) ; |
Tests sur les fichiers :
![]() | -d (catalogue), |
![]() | -f (fichier), |
![]() | -r (permissions de lire le fichier), |
![]() | -w (permissions d'écrire le fichier), |
![]() | -x (permissions d'exécuter le fichier). |
* exit <valeur entière> termine le processus et renvoie
la valeur passée en paramètre comme code de retour.
set 'ls'
for i in $*
do
if [ -d $i ]
then echo "$i est un repertoire"
fi
if [ $i = "toto" ]
then echo "toto trouve. Voulez-vous voir son contenu ?"
read rep
case $rep in
o | O ) cat $i;;
n | N ) echo "pas de visualisation du contenu de toto";;
* ) echo "vous repondez vraiment n importe quoi"
esac
fi
done
chaine=$1
ps | grep $chaine | grep -v grep |
while read pid reste
do
kill -9 $pid
done
L'exécution de ce fichier de commandes s'effectue en appelant monscript2 avec les paramètres souhaités.
par exemple : monscript2 pgm_qui_boucle.
Cette exécution tue tous les processus qui s'appellent pgm_qui_boucle.
.
.
Le système UNIX est avant tout une collection d'appels système sur les fichiers, processus, entrées/sorties, communications inter-processus, communications réseaux, etc. (documentés dans la section 2 du main)
Chaque appel se présente comme un appel de fonction.
Le traitement d'un appel systèmes provoque un passage en mode système (ou noyau).
Lorsque le traitement de l'exception se termine, le processeur repasse en mode utilisateur et on revient exécuter l'instruction se trouvant immédiatement derrière l'appel système.
La plupart des appels systèmes retournent une valeur qui indique le succès ou l'échec de l'opération demandée. En cas d'échec la cause exacte de l'échec peut être précisée par le contenu de la variable globale errno disponible en incluant le fichier <errno.h>. Celui-ci contient également la liste des codes d'erreur.
.
.
.
Tout fichier est défini par un descripteur de fichier unique appelé i-noeud. Il contient les informations d'ordre général concernant le fichier :
![]() | taille ; |
![]() | adresse des blocs utilisés sur le disque ; |
![]() | identification du propriétaire ; |
![]() | permissions d'accès ; |
![]() | type de fichier (fichier ordinaire, catalogue, ...) ; |
![]() | date de dernière modification ; |
![]() | compteur de références à ce fichier dans un répertoire. |
L'i-noeud ne contient aucun nom pour le fichier.
Un fichier n'est effectivement détruit (espace disque et i-noeud récupérés par le système) que si le compteur de références du i-noeud du fichier devient nul.
.
* set-uid permet d'exécuter un programme avec les privilèges de son propriétaire et non pas ceux de l'utilisateur qui lance l'exécution.
* set-gid : même chose avec le groupe ;
* bit de collage (sticky bit) assure le maintien du programme en mémoire même lorsque aucun processus actif ne correspond à une exécution du programme.
Un ficher régulier UNIX peut être considéré comme un tableau de caractères et les opérations de lecture/écriture se font à partir d'un "pointeur de position" qui pointe sur le premier caractère lors de l'ouverture et est ensuite avancé au fur et à mesure des lectures et des écritures.
Toute utilisation d'un fichier commence par une ouverture qui renvoie un "file descriptor" traduit ici par "numéro de fichier ouvert" qui n'est que le numéro de l'entrée qui contient un pointeur vers l'inoeud du fichier, dans la table des fichiers ouverts.
Après ouverture, un programme désigne un fichier non plus par une référence relative ou absolue mais par le numéro de l'entrée dans la table.
Avantage : inutile de retraduire le nom a chaque opération sur le fichier.
* int open(char *référence ,int mode, int permis)
Exemple :
int nf;
nf = open("projet.pas", O_RDWR);
* int close (int no_fichier);
Exemple :
.
* int read(int no_fichier, char *adr_zone, int nb);
Exemple :
* int write(int no_fichier, char *adr_zone, int nb);
Exemple :
int nb;
char c,tab[8]="bonjour";
nb = write(1,&c,1);
nb = write(nf,tab,sizeof tab);
* long lseek(int no_fichier, long déplacement, int drapeau);
.
.
.
creat : création d'un fichier.
link : création d'un lien physique sur un fichier.
unlink : suppression d'un lien physique sur un fichier et suppression du fichier si c'était le dernier lien existant.
dup : duplication d'une entrée dans la table des fichiers ouverts dans la première entrée disponible.
chdir : changement de répertoire de travail.
chown : changement de propriétaire de fichier.
chmod : changement de permission d'accès.
flush : vide un tampon d'entrée/sortie.
stat : donne attributs d'un fichier (type, propriétaire, permission d'accès, etc).
umask : modification du "masque" des permissions d'accès utilisé lors des créations de fichiers.
mknod : création d'un répertoire.
mount : montage d'une arborescence d'un volume amovible.
tar : création, modification et lecture d'archives.
Un tube est un fichier sans nom géré par le système
Exemple :
Un tube ne peut être utilisé que par le processus qui l'a créé ou par ses descendants (du fait de son absence de nom).
L'écriture et la lecture dans un tube se font en utilisant les appels normaux read() et write() avec comme paramètre le numéro de fichier correspondant.
Lors d'une lecture, le nombre d'octets effectivement lus est le minimum du nombre demandé et du nombre disponible. Le système se charge de suspendre tout processus qui tente de lire dans un tube vide jusqu'à l'introduction de nouveau octets ou la fermeture définitive du tube en écriture. De même pour l'écriture.