Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Programmation shell sous Unix/Linux
  3. Mécanismes essentiels du shell
Extrait - Programmation shell sous Unix/Linux ksh, bash, norme POSIX (avec exercices corrigés) (7e édition)
Extraits du livre
Programmation shell sous Unix/Linux ksh, bash, norme POSIX (avec exercices corrigés) (7e édition)
1 avis
Revenir à la page d'achat du livre

Mécanismes essentiels du shell

Présentation

Ce chapitre présente et explique de manière détaillée les fonctionnalités de base du shell couramment utilisées dans les commandes Unix.

Commandes internes et externes

Une commande Unix appartient à l’une des deux catégories suivantes.

1. Les commandes externes

Une commande externe est un fichier localisé dans l’arborescence. Par exemple, lorsqu’un utilisateur lance la commande ls, le shell demande au noyau Unix de charger en mémoire le fichier /usr/bin/ls.

Sont considérés comme commandes externes les fichiers possédant l’un des formats suivants :

  • Fichiers au format binaire exécutable.

  • Fichiers au format texte représentant un script de commandes (qui peut être écrit en shell ou dans un autre langage tel que Python, Perl...).

La commande file donne une indication sur le type de données contenues dans un fichier.

Exemples

La commande ls est un fichier au format binaire exécutable. Résultat de la commande file :

$ file /bin/ls 
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), 
dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped 

La commande monscript.sh est un script shell. Résultat de la commande file :

$ file /home/christie/monscript.sh 
monscript.sh: ascii text 

La commande monscript.pl est un script Perl. Résultat de la commande file :

$ file /home/christie/monscript.pl 
monscript.pl: ascii text 

L’argument de la commande file est un nom de fichier exprimé en relatif ou en absolu.

Les commandes externes sont exécutées par l’intermédiaire d’un shell enfant (cf. Figure 1).

images/02ri01.png

Figure 1 : Exécution d’une commande externe

Les interpréteurs shell sont développés en Langage C. La fonction fork() du C permet à un processus de se dupliquer. La fonction exec() permet à un processus de se faire remplacer par un autre.

2. Les commandes internes

Une commande interne est un mot-clé du shell. C’est donc le shell qui exécute l’action....

Affichage à l’écran

1. La commande echo

bourne

posix

ksh

bash

La commande interne echo permet de réaliser des affichages à l’écran.

Exemple

$ echo Voici un livre sur la programmation shell! 
Voici un livre sur la programmation shell! 
$ 

Certains caractères ont, lorsqu’ils sont placés entre quotes (apostrophes ou guillemets), une signification spéciale. Ce sont des caractères d’échappement. La commande echo du bash devra être avec l’option-e pour que l’interprétation de ces caractères ait lieu.

Liste des caractères d’échappement

Caractère d’échappement

Signification

\\

Antislash

\a

Sonnerie

\b

Effacement du caractère précédent

\c

Suppression du saut de ligne en fin de ligne

\f

Saut de page

\n

Saut de ligne

\r

Retour chariot

\t

Tabulation horizontale

\v

Tabulation verticale

\0xxx

Valeur d’un caractère exprimée en octal

a. Le caractère \n

Il sert à provoquer un saut de ligne.

Exemples avec un Bourne ou Korn shell

$ echo "Voici un saut de ligne\net encore un autre\net le saut de 
ligne naturel de la commande echo"  
Voici un saut de ligne 
et encore un autre 
et le saut de ligne naturel de la commande echo 
$ 

Les quotes sont obligatoires :

$ echo a\nb 
anb 
$ echo "a\nb" 
a 
b 
$ 

Exemples avec un bash

$ echo "a\nb" 
a\nb 
$ echo -e "a\nb" 
a 
b 
$ 

b. Le caractère \c

Il sert à éliminer le saut de ligne naturel de la commande echo.

Le caractère \c doit se situer impérativement en dernière position de l’argument de echo (juste avant le guillemet fermant).

Exemples avec un Bourne ou Korn shell

$ echo "Premiere ligne" ; echo "Deuxieme ligne" 
Premiere ligne ...

Le caractère ~ (tilde)

ksh

bash

Le caractère ~ représente le répertoire d’accueil de l’utilisateur courant.

Exemples

L’utilisateur courant se nomme christie :

$ id 
uid=505(christie) gid=505(ociensa) 

Le répertoire courant est /tmp :

$ pwd  
/tmp 

Copie du fichier /tmp/f1 dans le répertoire d’accueil (/home/christie) :

$ cp f1 ~ 

Copie du fichier /tmp/f1 sous le répertoire /home/christie/docs :

$ cp f1 ~/docs 

Si le caractère ~ est immédiatement suivi d’un mot, ce dernier est considéré comme un nom d’utilisateur.

Exemples

Recopier le fichier f1 sous le répertoire d’accueil de l’utilisateur sebastien (nous supposons que les permissions adéquates sont positionnées) :

$ cp f1 ~sebastien 
$ ls /home/sebastien/f1 
f1 
$ 

Recopier le fichier f1 sous le répertoire /home/sebastien/rep :

$ cp f1 ~sebastien/rep 
$ ls /home/sebastien/rep 
f1 

La commande interne cd

Nous présentons ici les syntaxes particulières de la commande cd.

posix

ksh

bash

Nous présentons ici les syntaxes particulières de la commande cd.

Exemples

La commande cd sans argument permet à l’utilisateur de revenir dans son répertoire d’accueil :

$ cd 

Même chose en utilisant le caractère ~ :

$ cd ~ 

Se déplacer dans le répertoire d’accueil de l’utilisateur sebastien :

$ pwd 
/home/christie 
$ cd ~sebastien 
$ pwd 
/home/sebastien 

Revenir dans le répertoire précédent avec cd - :

$ cd - 
/home/christie 

Substitution de noms de fichiers

De nombreuses commandes prennent des noms de fichier en argument. Ces derniers peuvent être cités littéralement ou être spécifiés de manière plus générique. Le shell propose un certain nombre de caractères spéciaux qui permettent de fabriquer des expressions utilisées comme modèles de noms de fichier.

1. Expressions basiques

bourne

posix

ksh

bash

a. Le caractère *

Il représente une suite de caractères quelconques (entre 0 et n caractères).

Exemples

$ ls 
f12 f1.i FICa fic.c fic.s monscript.pl MONSCRIPT.pl ours.c 

Afficher tous les noms de fichier se terminant par .c :

$ ls *.c 
fic.c ours.c 

Afficher tous les noms de fichier commençant par la lettre f :

$ ls f* 
f12 f1.i fic.c fic.s 

b. Le caractère ?

Il représente un caractère quelconque.

Exemples

Afficher tous les noms de fichier ayant une extension composée d’un seul caractère :

$ ls *.? 
f1.i fic.c fic.s ours.c 

Afficher tous les noms de fichier composés de quatre caractères :

$ ls ???? 
f1.i FICa 

c. Les caractères [ ]

Une paire de crochets représente l’emplacement d’un seul caractère. Elle permet de spécifier la liste des caractères que l’on attend à une position bien précise dans le nom du fichier. Il est également possible d’utiliser les notions d’intervalle et de négation.

Exemples de syntaxe d’intervalles et de négation

Intervalles

[a-z]

une minuscule comprise entre a et z

[a-zB-F]

une minuscule comprise entre a et z OU une majuscule comprise entre B et F

[A-Z0-9i]

une majuscule OU un chiffre OU la lettre i

Négation

Le ! se positionne uniquement en première position à l’intérieur des crochets et exprime la négation...

Séparateur de commandes

Le caractère spécial ; du shell permet d’écrire plusieurs commandes sur une même ligne. Les commandes sont exécutées séquentiellement.

Exemple

$ pwd 
/home/christie 
$ ls 
$ mkdir rep ; cd rep ; pwd 
/home/christie/rep 

Redirections

Les redirections sont couramment utilisées dans les commandes Unix. Elles permettent de récupérer le résultat d’une ou de plusieurs commandes dans un fichier ou au contraire de faire lire un fichier à une commande. Cette partie expose de manière détaillée les différentes syntaxes possibles avec leur mécanisme interne associé.

Les redirections sont mises en place par le shell.

1. Entrée et sorties standards des processus

Les processus Unix ont, par défaut, leur fichier terminal ouvert trois fois, sous trois descripteurs de fichier différents. Un descripteur peut se voir comme un canal de communication.

a. Entrée standard

Le descripteur de fichier 0 est nommé également entrée standard du processus. Les processus qui attendent des informations de la part de l’utilisateur déclenchent une lecture sur le descripteur 0. Si ce dernier est associé au terminal, ce qui est le cas par défaut, cela se matérialise pour l’utilisateur par une demande de saisie au clavier.

La majorité des commandes utilisent l’entrée standard pour déclencher une saisie. Il existe cependant des exceptions. Par exemple, la commande passwd ouvre le fichier terminal sous un autre descripteur.

b. Sortie standard

Le descripteur de fichier 1 est nommé également sortie standard du processus. Par convention, un processus qui souhaite envoyer un message résultat à l’utilisateur doit le faire transiter via le descripteur 1. Si ce dernier est associé au terminal, ce qui est le cas par défaut, cela se matérialise pour l’utilisateur par un affichage à l’écran.

c. Sortie d’erreur standard

Le descripteur de fichier 2 est également nommé sortie d’erreur standard du processus. Par convention...

Tubes de communication

Un tube (pipe en anglais) permet de faire communiquer deux processus. Le tube est représenté par une barre verticale (combinaison de touches [Alt Gr] 6 sur un clavier AZERTY) située entre deux commandes Unix. Le résultat de la commande de gauche va partir dans le tube, tandis que la commande de droite va en extraire les données afin de les traiter.

Les figures 12 et 13 représentent le mécanisme interne associé au tube de communication. 

images/02ri12.png

Figure 9 : Mécanisme interne du tube de communication - Première étape

images/02ri13.png

Figure 10 : Mécanisme interne du tube de communication - Deuxième étape

Quelles que soient les commandes présentes de chaque côté du tube, le shell de travail détecte le caractère | sur la ligne de commande et va engendrer un shell enfant (1) qui, à son tour, va faire de même (2). Le premier shell enfant (PID=205) dissocie sa sortie standard du terminal et la connecte sur l’entrée du tube (3). Le deuxième shell enfant (PID=206) dissocie son entrée standard du terminal et la connecte sur la sortie du tube (4).

Chaque shell enfant va se remplacer avec sa commande (5a et 5b). Chaque commande commence alors à s’exécuter. Lorsque la commande who écrit sur sa sortie standard, les messages partent dans le tube (6a). Parallèlement, la commande mail lit son entrée standard (6b), ce qui provoque l’extraction des données contenues dans le tube.

Quelques remarques importantes

  • La sortie d’erreur standard de la commande de gauche ne part pas dans le tube.

  • Pour que l’utilisation d’un tube ait un sens, il faut que la commande placée à gauche du tube envoie des données sur sa sortie standard et que la commande placée à droite lise son entrée standard....

Regroupement de commandes

Le regroupement de commandes peut être utilisé pour :

  • rediriger la sortie écran de plusieurs commandes vers un même fichier ou vers un tube ;

  • faire exécuter plusieurs commandes dans le même environnement.

Exemple

Seule la sortie standard de la deuxième commande est redirigée dans le fichier resultat.

$ date ; ls > resultat 
ven. janv. 28 10:00:00 CET 2022 
$ cat resultat  
FIC 
fichier 
$ 

Les parenthèses ( ) et les accolades { } permettent de regrouper les commandes. Dans le premier cas, les commandes sont exécutées à partir d’un shell enfant, dans le deuxième cas à partir du shell courant.

1. Les parenthèses

Dans la plupart des cas, ce sont les parenthèses qui sont utilisées pour le regroupement de commandes.

Syntaxe

(cmde1 ; cmde2 ; cmde3) 

Avec les parenthèses, un shell enfant est systématiquement créé et c’est ce dernier qui traite la ligne de commande (avec duplications ultérieures si nécessaire). 

Premier exemple

Ici, l’utilisateur se sert des parenthèses pour rediriger la sortie standard de deux commandes :

$ (date ; ls) > resultat 
$ cat resultat 
lun. juin 13 17:23:50 CEST 2022 
FIC 
fichier 
$ 

Deuxième exemple

Le changement de répertoire est fait dans un shell enfant. Les commandes pwd et ls ont donc pour répertoire courant /tmp :

$ pwd 
/home/christie 
$ (cd /tmp ; pwd ; ls) > listefic 
$ cat listefic 
/tmp (résultat de pwd) 
dcopNYSrKn (liste des fichiers de /tmp) 
listetmp 
... 

Lorsque l’exécution des trois commandes est terminée, le shell de premier niveau reprend la main. Son répertoire courant est toujours /home/christie.

$ pwd 
/home/christie ...

Processus en arrière-plan

1. Principe

Les notions d’arrière-plan et d’avant-plan sont gérées par le shell.

Par défaut, les commandes sont lancées en avant-plan. Dans ce mode, le shell parent s’endort en attendant la fin de la commande. Il reprend la main uniquement lorsque la commande est terminée.

Le caractère & est un caractère spécial du shell qui permet de lancer la commande en arrière-plan. Le shell lance la commande et réaffiche immédiatement son prompt en attente d’une nouvelle commande. Comme le shell et la commande s’exécutent en parallèle et qu’ils sont tous deux liés au même terminal, il est conseillé de rediriger les sorties de la commande.

Exemple

Le shell affiche le PID de la commande (8247), ainsi que son index ([1]) dans la liste des tâches en arrière-plan lancées à partir de ce shell :

$ find / -size +2000 1>/tmp/resu 2 >/dev/null& 
[1] 8247 
$ 

Les processus qui s’exécutent en arrière-plan ne sont pas sensibles aux actions qui proviennent du clavier. Il est donc, par exemple, impossible de les tuer avec Ctrl C.

2. Contrôle de tâches (jobs)

jsh

(Bourne shell avec Job Control)

posix

ksh

bash

Le shell dispose de commandes internes permettant à l’utilisateur d’agir sur les tâches du terminal courant qui sont en avant ou en arrière-plan. Le tableau suivant liste ces fonctionnalités. 

Commande

Action

Touches [Ctrl] Z

Uniquement pour processus en avant-plan

Envoi du signal SIGTSTP :  Passe le processus du terminal courant dans l’état Stoppé : le processus est toujours en mémoire, mais l’exécution est figée. Les commandes fg et bg permettent de reprendre l’exécution....

Exercices

1. Fonctionnalités diverses

a. Exercice 1 : commandes internes et externes

Les commandes umask et chmod sont-elles des commandes internes ?

b. Exercice 2 : génération de noms de fichiers

Soit la liste de fichiers suivante :

$ ls 
bd.class.php    header.inc.php  install.txt     readme.txt 
essai           index.php       mail.class.php 

1.

Afficher les noms de fichiers se terminant par .php.

2.

Afficher les noms de fichiers ayant la lettre e en deuxième position.

3.

Afficher les noms de fichiers dont la première lettre est comprise entre a et e.

4.

Afficher les noms de fichiers qui ne commencent pas par une voyelle.

Expressions étendues (ksh, bash)

5.

Afficher les noms de fichiers qui ne se terminent pas par .php.

6.

Afficher les noms de fichiers qui ne se terminent ni par .txt ni par .php.

c. Exercice 3 : séparateur de commandes

Comment écrire les deux commandes suivantes sur la même ligne ?

$ cd /tmp 
$ ls -l 

2. Redirections

a. Exercice 1

Lister tous les processus du système et rediriger le résultat dans un fichier.

b. Exercice 2

Soit la commande who -A, qui génère un message d’erreur :

$ who -A 
who : option invalide -- 'A' 

1.

Relancer cette commande et rediriger les erreurs dans un fichier.

2.

Relancer cette commande et faire disparaître les erreurs, sans les rediriger dans un fichier disque.

c. Exercice 3

Exécuter les commandes suivantes :

$ touch fic_existe 
$ chmod 600 fic_existe  fic_existepas 
chmod: impossible d'accéder à "fic_existepas": Aucun fichier ou 
dossier de ce type 

1.

Rediriger les résultats de la commande chmod dans un fichier, les erreurs dans un autre.

2.

Rediriger les résultats et les erreurs de la commande dans un même fichier. 

d. Exercice 4

Que fait...