Shell Bash
Introduction
Malgré l’existence d’interfaces graphiques de plus en plus conviviales et ergonomiques, l’utilisation de la ligne de commande reste fréquente sous Linux.
L’apprentissage du shell permet au lecteur de mieux comprendre le fonctionnement du système et d’augmenter sa productivité en facilitant l’utilisation de ce dernier.
Ce chapitre passe en revue différentes fonctionnalités offertes par le shell Bash.
Généralités et définitions
Le shell
Le shell est le programme lancé automatiquement lorsqu’un utilisateur se connecte au système sur un terminal texte ; c’est lui qui fait le lien entre l’utilisateur et le système.
Le terme "shell" en anglais signifie "coquille", ce qui correspond bien à l’image d’encapsulation que l’on peut en avoir.
Le shell est aussi appelé "interpréteur de commandes" car :
-
C’est lui qui traduit au système les instructions soumises par l’utilisateur via la ligne de commande et qui présente les informations retournées à l’écran.
-
À la différence d’un compilateur utilisé en programmation (qui construit un fichier binaire compréhensible par le noyau Linux à partir d’un ensemble d’instructions contenues dans le code source), le shell interprète et exécute chaque commande au fur et à mesure que l’utilisateur les saisit.
Il existe plusieurs shells disponibles sous Linux, notamment :
-
Bourne Shell ou sh : c’est le premier shell écrit pour Unix par Steve Bourne. Aujourd’hui vieillissant, il reste cependant le shell de référence sous Unix, et plusieurs interpréteurs de commandes récents ont gardé une compatibilité avec celui-ci....
Variables
Véritable langage de programmation, le shell Bash fournit tous les éléments nécessaires au développement d’applications ; cette section traite des variables.
Une variable est un paramètre pouvant évoluer pendant l’exécution d’un programme ; on lui donne un nom de façon à repérer la valeur qu’elle représente.
1. Manipulation de variables
Nommage
Le nom d’une variable est un mot composé exclusivement de caractères alphanumériques et du soulignement _ (underscore), commençant par une lettre ou un soulignement.
Par convention, l’utilisateur nommera les variables avec des caractères en minuscules car les majuscules sont généralement employées pour les noms des variables d’environnement.
Comme pour les noms de fichiers, il est préférable de donner des noms explicites aux variables afin de rendre la maintenance des scripts générés plus aisée.
Affectation
Une variable nommée var peut recevoir une valeur valeur par une affectation de la forme var=valeur.
Il n’y a pas d’espace avant ou après le caractère = et si la valeur est composée de plusieurs mots ou de caractères spéciaux, elle doit être encadrée par des caractères de citation (cf. la section Caractères de citation de ce chapitre).
Une variable existe dès qu’on lui attribue une valeur ; cette valeur peut être un nombre, un mot ou encore une chaîne de caractères contenant n’importe quel caractère spécial :
[nicolas]$ var1=12
[nicolas]$ var2=mot
[nicolas]$ var3="deux mots"
[nicolas]$ var4='car. spéciaux : $* ?{}()[]"\&~|`^!=%,.;#'
Si aucune valeur n’est fournie, la variable reçoit une chaîne vide ; les deux syntaxes suivantes sont équivalentes :
[nicolas]$ var5=""
[nicolas]$ var6=
Appel et affichage
Le shell remplace une variable par sa valeur si son nom précédé du caractère $ apparaît sur la ligne de commande et ce, avant même d’interpréter la commande passée :
[nicolas]$ echo $var2
mot
L’interprétation de la ligne de commande par le shell...
Caractères génériques
Les caractères génériques sont des caractères spéciaux dédiés à l’écriture de motifs dans les noms de fichiers.
Ils permettent d’effectuer une recherche suivant un motif sur les noms de fichiers présents dans le répertoire courant.
Les exemples de cette section sont fondés sur un répertoire contenant les fichiers suivants :
[nicolas]$ ls -a
. banc bleu fic1 fic2.4 .os rose
.. blanc exemples fic2 fic2.7 rond rouge
L’astérisque : *
Lorsque le Bash rencontre ce caractère sur la ligne de commande, il le substitue par une chaîne de caractères (pouvant être de longueur nulle), de façon à énumérer tous les noms de fichiers correspondant au motif dans le répertoire courant.
Ainsi, le motif r*e est remplacé par tous les noms de fichiers commençant par le caractère r et finissant par le caractère e :
[nicolas]$ ls r*e
rose rouge
Le signe * remplace n’importe quel caractère dans le motif sauf le . (point) en première position dans le nom de fichier ; par exemple, le motif *s correspond au fichier exemples mais pas au fichier .os :
[nicolas]$ ls *s
exemples
L’exclusion du premier point par le caractère générique * évite notamment la suppression des fichiers cachés avec la commande rm * ; le but des noms de fichiers commençant par un point étant justement de masquer des fichiers dont on ne veut plus se soucier (mais probablement pas supprimer).
Un motif peut être composé de plusieurs caractères génériques ; en répétant l’astérisque, on obtient par exemple *e* qui concorde avec tous les fichiers contenant au moins un e dans leur nom :
[nicolas]$ ls *e*
bleu exemples rose rouge
Enfin, si le shell ne trouve aucune correspondance avec le motif dans les noms de fichiers présents dans le répertoire courant, ce motif est transmis tel quel à la commande :
[nicolas]$ ls *zork ...
Caractères de citation
Les caractères de citation sont utilisés pour modifier l’interprétation du shell de certains autres caractères. Ainsi, un caractère spécial peut être interprété littéralement et non de manière symbolique.
Cela permet à certains programmes et utilitaires de réinterpréter ou étendre les caractères spéciaux passés sur la ligne de commande sans que le shell ne les interprète lui-même.
Les commandes grep et find décrites plus loin dans l’ouvrage, usent particulièrement des caractères de citation.
Les apostrophes : ’
Tous les caractères spéciaux présents entre apostrophes sont ignorés par le shell.
Par exemple :
[nicolas]$ echo variable $HOME et asterix *
variable /home/nicolas et asterix banc blanc bleu exemples fic1 fic2
fic2.4 fic2.7 rond rose rouge
[nicolas]$ echo 'variable $HOME et asterix *'
variable $HOME et asterix *
Les guillemets : "
Comme pour les apostrophes tous les caractères spéciaux entre guillemets sont ignorés à l’exception cette fois-ci de $, ` (accent grave) et \ :
[nicolas]$ echo "variable $HOME et asterix *"
variable /home/nicolas et asterix *
L’antislash : \
Tout caractère suivant l’antislash perd sa signification spéciale...
Redirections
1. Descripteurs de fichiers
Tout processus lancé sous Linux est associé à trois descripteurs de fichiers permettant de gérer les entrées, les sorties et les erreurs standards.
On appelle descripteur de fichier un pointeur vers un fichier. Un programme accédant à un fichier pour y lire ou écrire des données doit préalablement associer (via un appel système) un descripteur de fichier à un fichier ; il utilise alors ce descripteur comme point d’entrée (lecture) ou de sortie (écriture) pour les données qu’il doit traiter.
On appelle "entrées" les paramètres traités par le processus et "sorties" les résultats obtenus. Les "erreurs" correspondent à un résultat provenant d’une erreur de traitement de la part du processus. Les trois descripteurs de fichiers correspondants sont aussi identifiés par un numéro : 0 pour l’entrée, 1 pour la sortie et 2 pour l’erreur :
Par exemple, si on considère l’opération "8 divisé par 2", un processus effectuant ce calcul présentera en entrée l’opération à réaliser "8/2" et en sortie le résultat "4" :
Si on donne maintenant l’opération "5/0" à ce processus, il retournera en erreur un message indiquant qu’une division par zéro n’est pas admise :
Les périphériques sous Linux étant représentés par des fichiers dans le répertoire /dev, les trois descripteurs de fichiers associés par défaut à un processus sont :
-
Le clavier en entrée standard pour que l’utilisateur puisse saisir les données et paramètres à traiter.
-
Le terminal en sortie standard pour afficher les résultats de la commande.
-
Le terminal en erreur standard pour que l’utilisateur soit informé qu’une erreur de traitement s’est produite.
Ces descripteurs peuvent être redéfinis ; on appelle cette opération "redirection".
2. Redirection de l’entrée standard
Pour rediriger l’entrée standard d’un processus afin qu’il ne traite plus les données à partir...
Alias
L’ensemble des redirections vues dans ce chapitre montre la logique Unix dans la mise à disposition d’outils atomiques (dédiés à une seule fonction). Ces derniers peuvent être associés afin de former des commandes plus complexes et adaptées aux besoins de l’utilisateur.
Cependant, certaines lignes de commande peuvent rapidement s’allonger et une utilisation fréquente d’une telle syntaxe peut se révéler rapidement rébarbative. Il est néanmoins possible de simplifier le travail de l’utilisateur en définissant des alias de commandes.
Un alias est caractérisé par un nom (généralement simple) qui sera remplacé par une commande (généralement complexe ou longue).
La liste des alias existants peut être dressée en exécutant la commande alias sans argument :
[nicolas]$ alias
alias cd..='cd ..'
alias cp='cp -i'
alias d='ls'
alias df='df -h -x supermount'
alias du='du -h'
alias kde='xinit /usr/bin/startkde'
alias l='ls'
alias la='ls -a'
alias ll='ls -l'
alias ls='ls -F --color=auto'
alias lsd='ls -d */'
alias mc='. /usr/share/mc/bin/mc-wrapper.sh'
alias md='mkdir'
alias...
Exécution de commandes
Les commandes saisies par l’utilisateur peuvent être de natures différentes :
-
alias ;
-
commande interne ;
-
commande externe.
1. Commandes internes du shell
On qualifie d’internes les commandes intégrées au shell. Leur exécution ne génère pas de sous-processus.
Les commandes internes sont essentiellement composées d’outils permettant de modifier l’environnement du shell : changement du répertoire courant (cd), définition de variables (set, unset, etc.) et d’alias (alias, unalias), structures de contrôle (if, for, while, etc.), etc.
La liste exhaustive des commandes internes comprises avec le shell Bash est : :, ., alias, bg, bind, break, builtin, caller, case, cd, command, compgen, complete, compopt, continue, coproc, declare, dirs, disown, echo, enable, eval, exec, exit, export, false, fc, fg, for, function, getopts, hash, help, history, if, jobs, kill, let, local, logout, mapfile, popd, printf, pushd, pwd, read, readarray, readonly, return, select, set, shift, shopt, source, suspend, test, time, trap, true, type, typeset, ulimit, umask, unalias, unset, until, wait, while.
La page de manuel du Bash (man bash) détaille les commandes internes qui ne sont pas étudiées dans cet ouvrage.
2. Commandes externes
Les commandes externes regroupent tous les fichiers exécutables présents...
Substitution de commandes
La substitution de commandes consiste à récupérer la sortie d’une commande sur la ligne de commande. Les sorties de commandes peuvent alors être utilisées pour l’affectation d’une variable ou comme argument d’une autre commande.
Le shell effectue les substitutions de commandes avant d’interpréter la ligne de commande dans son intégralité.
La syntaxe classique d’une substitution de commandes utilise l’apostrophe inverse (ou accent grave, ou "back quote") obtenue avec la combinaison de touches [AltGr]+[7] sur un clavier français :
[nicolas]$ whoami
nicolas
[nicolas]$ echo "mon login est `whoami`"
mon login est nicolas
[nicolas]$ monlogin=`whoami`
[nicolas]$ echo "mon login est $monlogin"
mon login est nicolas
L’avantage d’affecter la sortie d’une commande à une variable est de pouvoir réutiliser plusieurs fois ce résultat en n’ayant évalué qu’une seule fois la commande.
La seconde syntaxe admise pour la substitution de commandes est $(). L’avantage de cette syntaxe est de pouvoir imbriquer les substitutions de commandes :
[nicolas]$ echo "contenu de mon répertoire : $(ls /home/$(whoami))"
contenu de mon répertoire : blanc
bleu
jaune
marron
rouge ...
Options du shell Bash
Le comportement du shell Bash peut être modifié par l’activation d’options.
La syntaxe générale, pour activer une option, est set -o option. Pour désactiver une option, utilisez set +o option.
Bien que cela semble illogique - le signe moins étant le caractère initialement prévu pour introduire les options des commandes Unix - c’est le + qui est utilisé ici pour la désactivation.
L’état des différentes options du shell peut être affiché à l’aide de la commande set -o seule :
[nicolas]$ set -o
allexport off
braceexpand on
emacs on
errexit off
errtrace off
functrace off
hashall on
histexpand on ...
Exercices
Exercice 1
Affichez en une seule commande tous les fichiers présents dans le répertoire /etc dont le nom commence par la lettre p, ou se termine par la lettre d précédée d’un point.
Solution
Il faut utiliser les caractères génériques pour créer le motif correspondant à l’énoncé :
[nicolas]$ ls -d /etc/{p*,*.d}
/etc/bash_completion.d /etc/passwd /etc/purple
/etc/binfmt.d /etc/passwd- /etc/rc0.d
/etc/chkconfig.d /etc/passwdqc.conf /etc/rc1.d
/etc/cron.d /etc/pcmcia /etc/rc2.d
/etc/depmod.d /etc/pinforc /etc/rc3.d
/etc/dnsmasq.d /etc/pkcs11 /etc/rc4.d
/etc/dracut.conf.d /etc/pki /etc/rc5.d ...