Chapitre 1. Introduction à Bash

Table des matières

1.1. Les shells
1.1.1. Un environnement de travail
1.1.2. Un langage de programmation
1.1.3. Atouts et inconvénients des shells
1.1.4. Shell utilisé
1.2. Syntaxe d’une commande
1.3. Commandes internes et externes
1.3.1. Commandes internes
1.3.2. Commandes externes
1.4. Modes d’exécution d’une commande
1.4.1. Exécution séquentielle
1.4.2. Exécution en arrière-plan
1.5. Commentaires
1.6. Fichiers shell

1.1. Les shells

Sous Unix, on appelle shell l’interpréteur de commandes qui fait office d'interface entre l'utilisateur et le système d’exploitation. Les shells sont des interpréteurs : cela signifie que chaque commande saisie par l’utilisateur (ou lue à partir d’un fichier) est syntaxiquement vérifiée puis exécutée.

Il existe de nombreux shells qui se classent en deux grandes familles :

  • la famille C shell (ex : csh, tcsh)

  • la famille Bourne shell (ex : sh, bash, ksh, dash).

zsh est un shell qui contient les caractéristiques des deux familles précédentes. Néanmoins, le choix d’utiliser un shell plutôt qu’un autre est essentiellement une affaire de préférence personnelle ou de circonstance. En connaître un, permet d’accéder aisément aux autres. Lorsque l’on utilise le système GNU/Linux (un des nombreux systèmes de la galaxie Unix), le shell par défaut est bash (Bourne Again SHell). Ce dernier a été conçu en 1988 par Brian Fox dans le cadre du projet GNU [2]. Aujourd’hui, les développements de bash sont menés par Chet Ramey.

Un shell possède un double aspect :

  • un aspect environnement de travail

  • un aspect langage de programmation.

1.1.1. Un environnement de travail

En premier lieu, un shell doit fournir un environnement de travail agréable et puissant. Par exemple, bash permet (entre autres) :

  • le rappel des commandes précédentes (gestion de l’historique) ; cela évite de taper plusieurs fois la même commande

  • la modification en ligne du texte de la commande courante (ajout, retrait, remplacement de caractères) en utilisant les commandes d’édition de l’éditeur de texte vi ou emacs

  • la gestion des travaux lancés en arrière-plan (appelés jobs) ; ceux-ci peuvent être démarrés, stoppés ou repris suivant les besoins

  • l’initialisation adéquate de variables de configuration (chaîne d’appel de l’interpréteur, chemins de recherche par défaut) ou la création de raccourcis de commandes (commande interne alias).

Illustrons cet ajustement de configuration par un exemple. Le shell permet d’exécuter une commande en mode interactif ou bien par l'intermédiaire de fichiers de commandes (scripts). En mode interactif, bash affiche à l’écran une chaîne d’appel (appelée également prompt ou invite), qui se termine par défaut par le caractère # suivi d’un caractère espace pour l’administrateur système (utilisateur root) et par le caractère $ suivi d’un caractère espace pour les autres utilisateurs. Cette chaîne d’appel peut être relativement longue.

sanchis@jade:/bin$

Celle-ci est constituée du nom de connexion de l’utilisateur (sanchis), du nom de la machine sur laquelle l’utilisateur travaille (jade) et du chemin absolu du répertoire courant de l’utilisateur (/bin). Elle indique que le shell attend que l’utilisateur saisisse une commande et la valide en appuyant sur la touche entrée. Bash exécute alors la commande puis réaffiche la chaîne d’appel.

Si l’on souhaite raccourcir cette chaîne d’appel, il suffit de modifier la valeur de la variable prédéfinie du shell PS1 (Prompt Shell 1).

sanchis@jade:/bin$ PS1='$ '
$ pwd
/bin  => pwd affiche le chemin absolu du répertoire courant
$

La nouvelle chaîne d’appel est constituée par le caractère $ suivi d’un caractère espace.

1.1.2. Un langage de programmation

Les shells ne sont pas seulement des interpréteurs de commandes mais également de véritables langages de programmation. Un shell comme bash intègre :

  • les notions de variable, d’opérateur arithmétique, de structure de contrôle, de fonction, présentes dans tout langage de programmation classique, mais aussi

  • des opérateurs spécifiques (ex : |&)

$ a=5  => affectation de la valeur 5 à la variable a
$
$ echo $((a +3 ))  => affiche la valeur de l’expression a+3
8
$

L’opérateur |, appelé tube, est un opérateur caractéristique des shells et connecte la sortie d’une commande à l’entrée de la commande suivante.

$ lpstat -a
HP_Laserjet-2420 accepte des requêtes depuis jeu. 13 janvier 2022 12:22:45 CET
HP_Laserjet_P3005 accepte des requêtes depuis jeu. 13 janvier 2022 12:23:34 CET
$ 
$ lpstat -a | wc -l
2
$

La commande unix lpstat permet de connaître les noms et autres informations relatives aux imprimantes accessibles. La commande unix wc munie de l’option l affiche le nombre de lignes qu’elle a été en mesure de lire.

En connectant avec un tube la sortie de lpstat -a à l’entrée de la commande wc –l, on obtient le nombre d'imprimantes accessibles sur le réseau.

Même si au fil du temps de nouveaux types de données comme les entiers ou les tableaux ont été introduits dans certains shells, ces derniers manipulent essentiellement des chaînes de caractères : ce sont des langages de programmation orientés chaînes de caractères. C’est ce qui rend les shells à la fois si puissants et si délicats à utiliser.

L’objet de ce document est de présenter de manière progressive les caractéristiques de bash comme langage de programmation.

1.1.3. Atouts et inconvénients des shells

L’étude d’un shell tel que bash en tant que langage de programmation possède plusieurs avantages :

  • c’est un langage interprété : les erreurs peuvent être facilement localisées et traitées ; d’autre part, des modifications de fonctionnalités sont facilement apportées à l’application sans qu’il soit nécessaire de recompiler et faire l’édition de liens de l’ensemble

  • le shell manipule essentiellement des chaînes de caractères : on ne peut donc construire des structures de données complexes à l’aide de pointeurs, ces derniers n’existant pas en shell. Ceci a pour avantage d’éviter des erreurs de typage et de pointeurs mal gérés. Le développeur raisonne de manière uniforme en termes de chaînes de caractères

  • le langage est adapté au prototypage rapide d’applications : les tubes, les substitutions de commandes et de variables favorisent la construction d’une application par assemblage de commandes préexistantes dans l’environnement Unix

  • c’est un langage « glu » : il permet de connecter des composants écrits dans des langages différents. Ils doivent uniquement respecter quelques règles particulièrement simples. Le composant doit être capable :

    • de lire sur l’entrée standard,

    • d’accepter des arguments et options éventuels,

    • d’écrire ses résultats sur la sortie standard,

    • d’écrire les messages d’erreur sur la sortie standard dédiée aux messages d’erreur.

Cependant, bash et les autres shells en général ne possèdent pas que des avantages :

  • issus d’Unix, système d’exploitation écrit à l’origine par des développeurs pour des développeurs, les shells utilisent une syntaxe « ésotérique » d’accès difficile pour le débutant

  • suivant le contexte, l’oubli ou l’ajout d’un caractère espace provoque facilement une erreur de syntaxe

  • bash possède plusieurs syntaxes pour implanter la même fonctionnalité, comme la substitution de commande ou l’écriture d’une chaîne à l’écran. Cela est principalement dû à la volonté de fournir une compatibilité ascendante avec le Bourne shell, shell historique des systèmes Unix

  • certains caractères spéciaux, comme les parenthèses, ont des significations différentes suivant le contexte ; en effet, les parenthèses peuvent introduire une liste de commandes, une définition de fonction ou bien imposer un ordre d’évaluation d’une expression arithmétique. Toutefois, afin de rendre l’étude de bash plus aisée, nous n’aborderons pas sa syntaxe de manière exhaustive ; en particulier, lorsqu’il existera plusieurs syntaxes pour mettre en oeuvre la même fonctionnalité, seule la syntaxe la plus lisible sera présentée, parfois au détriment de la portabilité vers les autres shells ou de la compatibilité POSIX.

1.1.4. Shell utilisé

La manière la plus simple de connaître le shell que l’on utilise est d’exécuter la commande unix ps qui liste les processus attachés à la fenêtre courante de l’utilisateur :

$ ps
PID TTY         TIME CMD
6908 pts/4  00:00:00 bash => l’interpréteur utilisé est bash
6918 pts/4  00:00:00 ps
$

Comme il existe plusieurs versions de bash présentant des caractéristiques différentes, il est important de connaître la version utilisée. Pour cela, on utilise l'option –-version de bash.

$ bash --version
GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu) 
Copyright (C) 2020 Free Software Foundation, Inc. 
Licence GPLv3+ : GNU GPL version 3 ou ultérieure 
	...
$

La version de bash qui sera utilisée est la version 5.1.



[2] http://www.gnu.org