Le shell et les commandes GNU
Le shell bash
1. Rôle du shell
Même si toutes les distributions proposent des interfaces utilisateur graphiques, un informaticien professionnel travaillant sur un système Linux doit connaître le fonctionnement de l’interpréteur de commandes (shell) et des principales commandes en mode caractère. D’une part, les systèmes serveurs sont généralement installés sans interface graphique, d’autre part il est indispensable de pouvoir gérer les scripts d’exploitation et d’administration écrits en langage shell et combinant des commandes en mode caractère.
L’interpréteur de commandes permet d’exécuter des instructions saisies au clavier ou lues dans un fichier script. Cet interpréteur est le plus souvent un programme de type shell. Le terme shell (coquille), d’origine Unix, est employé en référence au terme kernel (noyau) : le shell est une interface « autour » du noyau Linux, fonctionnant en mode caractère.
Il existe plusieurs programmes de type shell, chacun disposant de spécificités propres. Le Bourne Shell, du nom de son créateur Steve Bourne, est le shell le plus ancien, écrit pour Unix. Le shell a ensuite été normalisé dans le cadre des normes POSIX.
Le shell de référence de la plupart des distributions Linux est le bash (Bourne Again Shell), mais il en existe de nombreux autres, dont :
-
sh : Bourne Shell
-
ksh : Korn Shell
-
csh : C Shell
-
zsh : Z Shell
-
ash : A Shell
-
dash : Debian Almquist Shell.
Le fichier /etc/shells fournit la liste des shells installés sur le système.
2. Bash : le shell Linux par défaut
Le shell bash est un dérivé du Bourne Shell. Il est conforme aux normes POSIX mais il ajoute de nombreuses extensions qui lui sont spécifiques.
Dans les distributions Debian récentes, le shell par défaut est le dash, une variante très proche du shell bash.
a. Un shell puissant et libre
Le bash, sous licence open source GNU, est fourni par défaut avec toutes les distributions Linux. Il existe même en version macOS et Windows (via la fonctionnalité Sous-système Windows pour Linux).
Le shell fonctionne en mode ligne de commande. Quand il est lancé...
La gestion des fichiers
Linux est, comme Unix, un système d’exploitation orienté fichier. Tout (ou presque) peut être représenté par un fichier, les données (fichiers de données de tout type comme une image ou un programme), les périphériques (terminaux, souris, clavier, carte son, etc.), les canaux de communication (sockets, tubes nommés), etc.
1. Le système de fichiers
Un système de fichiers (File System), définit la structure organisant la gestion des répertoires et fichiers sur tout ou partie d’un support de stockage. L’ensemble des supports de stockage activés (montés) constitue le système de fichiers global qui se présente sous forme d’une arborescence unique, structurée par des répertoires.
Exemple d’arborescence Linux
Le système de fichiers de Linux est hiérarchique. Il décrit une arborescence de répertoires et de sous-répertoires, en partant d’un élément de base appelé la racine (root).
2. Les différents types de fichiers
On distingue trois types de fichiers : ordinaire, répertoire, spécial.
a. Les fichiers ordinaires ou réguliers
Les fichiers ordinaires sont aussi appelés fichiers réguliers (ordinary, regular files). Ce sont des fichiers qui contiennent des données, ils sont considérés par le système comme étant une suite d’octets. Ils peuvent contenir du texte, des images, du son, un programme exécutable, etc.
La commande file permet d’obtenir des informations sur la nature du contenu d’un fichier.
Exemple
$ file /usr/bin/bash /etc /etc/passwd
/usr/bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=
5d82a44f2a4466ff21f763af86b004d1fcb3a8f1, for GNU/Linux 3.2.0, stripped
/etc: directory
/etc/passwd: ASCII text
Le suffixe (ou extension) d’un nom de fichier n’a aucune signification particulière pour le système. Il est facultatif.
Afficher le contenu d’un fichier texte
La commande cat NomFic affiche le contenu du fichier NomFic.
La commande ne vérifie pas que le fichier ne contient...
Rechercher des fichiers avec la commande find
La commande find permet de rechercher des fichiers au sein de l’arborescence du système de fichiers selon différents critères et peut exécuter une commande sur chaque élément correspondant à la recherche.
Syntaxe
find [PointDeDépart] [Options] [Expression]
La commande recherche dans toute l’arborescence à partir du répertoire de départ spécifié. Par défaut, elle cherche à partir du répertoire courant (le répertoire "."). Sans option particulière de recherche, elle affiche tous les éléments contenus dans l’arborescence à partir du répertoire de départ, y compris les éléments dont le nom commence par le caractère point.
La commande find ne s’arrête pas en cas d’erreur, elle affiche un message et passe à la recherche de l’élément suivant. Le plus souvent, le message indique que les droits d’accès du répertoire ne permettent pas à la commande de lister son contenu.
Exemple
Tous les éléments du répertoire de connexion :
$ cd
$ find
.
./.local
./.local/share
./.local/share/tracker
./.local/share/tracker/data
./.local/share/tracker/data/tracker-store.journal
./.local/share/tracker/data/tracker-store.ontology.journal
./.local/share/tracker/data/.meta.isrunning
./.local/share/gvfs-metadata
./.local/share/gvfs-metadata/uuid-f6d93569-f478-4a37-8387-aacdcb125a6f
[...]
./lien3
./.bashrc
./.profile
./.bash_logout
./rep2
./rep2/fic1
[...]
./lien1
./lien2
./.bash_history
./fic1
./paquets
./paquets/lynx_2.9.0dev.6-3~deb11u1_amd64.deb
1. Critères de recherche
Des options permettent de définir les critères de recherche. Ces critères, s’ils sont plusieurs, sont combinés entre eux par un ET (critère1 ET critère2).
a. Recherche par nom
-name permet une sélection par nom de fichier ou de répertoire. Il est possible d’utiliser les caractères génériques vus précédemment. Dans ce cas, le critère devrait être placé entre guillemets pour éviter...
L’éditeur vi
La plupart des fichiers de configuration de Linux sont des fichiers textes. D’autre part, il est fréquent d’avoir à créer ou à modifier des scripts shell. Les distributions Linux proposent différents éditeurs de texte, certains fonctionnant en mode graphique, d’autres en mode caractère. Parmi tous ces éditeurs, le plus utilisé est certainement vi (visual editor). D’origine Unix, créé par Bill Joy, il existe sur tous les systèmes de type Unix et est fourni avec toutes les distributions Linux.
1. Présentation
L’éditeur vi sous Linux se nomme vim (vi iMproved). Il est compatible avec vi, mais dispose de fonctionnalités supplémentaires. En général, la commande vi existe mais est associée à l’exécutable de vim.
Syntaxe
vi [options] Fichier [Fichier2 ...]
vi est un éditeur de textes qui fonctionne en mode caractère (même s’il existe des versions avec interface graphique). Cela permet de l’utiliser depuis un terminal.
2. Fonctionnement
Une fois dans l’éditeur, ce dernier gère trois modes de fonctionnement :
-
Mode commande : les saisies représentent des commandes. On y accède en appuyant sur [Echap]. Chaque touche ou combinaison de touches déclenche une action (suppression, insertion, déplacement, copier, coller, etc.).
-
Mode saisie : c’est le mode utilisé pour la saisie de texte.
-
Mode ligne de commande : une ligne en bas d’écran permet de saisir des commandes spéciales, validées avec la touche [Entrée]. On y accède depuis le mode commande avec la touche « : ».
Au démarrage de vi, l’éditeur est en mode commande. Les commandes de vi sont associées à une ou plusieurs touches : a, i, o, yy, p, dw, J, etc. vi distingue les majuscules des minuscules, par exemple les commandes o et O n’ont pas le même effet !
Pour passer du mode commande au mode saisie, il faut exécuter une commande d’ajout ou d’insertion : a, i, o, etc. Pour sortir du mode saisie et revenir en mode commande, il faut utiliser la touche [Echap].
3. Les commandes de base de vi
a. Passer en mode saisie
Les commandes suivantes passent l’éditeur...
Les redirections des entrées/sorties standards
Les concepts d’entrées/sorties standards et de redirection permettent une très grande souplesse dans la gestion des programmes s’exécutant sur Linux.
1. Les entrées/sorties standards
Un programme en cours d’exécution dispose de trois fichiers ouverts, un en lecture seule et deux en écriture. Ces trois fichiers constituent les entrées/sorties standards. Ils sont identifiés par le programme grâce à leur numéro de descripteur ou leur nom symbolique, 0 pour l’entrée standard stdin (fichier ouvert en lecture seulement), 1 pour la sortie standard stdout et 2 pour la sortie d’erreur standard stderr (fichiers ouverts en écriture seulement).
Un programme Linux non graphique utilise généralement ces entrées/sorties standard pour communiquer avec l’extérieur :
-
L’entrée standard, en lecture, lui permet si nécessaire de lire des informations pendant son exécution.
-
La sortie standard, en écriture, lui permet de fournir des résultats de traitement.
-
La sortie d’erreur standard, en écriture, lui permet de fournir des messages d’erreur ou des informations complémentaires à son traitement.
2. Les entrées/sorties standards par défaut
Par défaut, le shell associe l’écran...
La redirection
La redirection entrées/sorties standards est un mécanisme permettant d’étendre avec une grande souplesse les fonctionnalités des programmes exécutés sur Linux. En effet, on peut, au lancement du programme, spécifier les fichiers associés à ses entrées/sorties standards. Comme Linux est un système d’exploitation orienté fichier, tout ou presque peut être vu comme un fichier. On peut donc rediriger les lectures ou les écritures d’un programme vers un fichier ordinaire, un fichier spécial associé à un périphérique (écran, clavier, imprimante, lecteur de bandes, connexion réseau…), ou un autre programme (tube). Ce mécanisme est transparent pour le programme, qui utilise ses entrées/sorties standards en lecture ou en écriture, sans savoir à quels fichiers elles correspondent.
1. Redirection de la sortie standard
Le caractère > permet de rediriger la sortie standard. On spécifie après ce caractère le chemin d’accès du fichier à associer à la sortie standard.
Le shell ouvre en écriture le fichier spécifié, le créant s’il n’existe pas, le vidant de son contenu s’il existe. Il lance ensuite l’exécution de la commande, en associant le fichier à sa sortie standard.
Exemple
Redirection de la sortie standard de la commande ls :
$ ls -l > resultat
$ cat resultat
total 24
-rw-r--r-- 1 pba pba 7 16 mai 12:11 fic1
-rw-rw-rw- 1 pba pba 0 17 mai 09:39 ficPublic
lrwxrwxrwx 1 pba pba 4 16 mai 12:10 lien1 -> fic1
-rw-r--r-- 1 pba pba 27 16 mai 11:53 lien2
-rw-r--r-- 1 pba pba 27 16 mai 11:50 lien3
drwxr-xr-x 2 pba pba 4096 16 mai 11:46 paquets
drwxr-x--- 2 pba pba 4096 17 mai 09:52 rep1
drwxr-xr-x 2 pba pba 4096 16 mai 08:12 rep2
-rw-r--r-- 1 pba pba 0 19 mai 14:21 resultat
La commande n’a rien affiché, elle a écrit ses résultats sur sa sortie standard, c’est-à-dire...
Les commandes filtres
Un filtre est un programme capable de lire des données sur son entrée standard et d’écrire ses résultats sur la sortie standard. C’est le cas de très nombreuses commandes utilitaires de Linux. Avec les tubes et les redirections, on peut ainsi combiner facilement des commandes pour effectuer des traitements divers, en particulier sur des fichiers texte.
1. Compter des lignes, des mots, des caractères
La commande wc (word count) permet de compter les lignes, les mots et les caractères des fichiers passés en argument, ou des lignes lues sur son entrée standard.
Syntaxe
wc [-l|c|w] [fic1 ... ficN]
-
-l : nombre de lignes.
-
-c : nombre d’octets.
-
-w : nombre de mots.
-
-m : nombre de caractères.
Exemple
$ wc liste
12 48 234 liste
Le fichier liste contient 12 lignes, 48 mots et 234 caractères.
Compter le nombre de lignes générées par une commande ls :
$ ls -l | wc -l
19
2. Sélection de lignes
Les commandes de type grep (Global Regular Expression Parser) permettent de sélectionner des lignes de textes en fonction de différents critères. Elles peuvent traiter des fichiers dont on leur passe le nom en argument, ou lire les données sur leur entrée standard.
Il s’agit d’extraire des lignes d’un fichier selon divers critères. Pour cela vous disposez de trois commandes : grep, egrep et fgrep qui lisent les données soit depuis un fichier d’entrée, soit depuis leur entrée standard.
a. grep
La syntaxe de la commande grep est :
grep [Options] modèle [Fichier1...]
Le modèle (pattern) est une chaîne de caractères formant une expression régulière. Elle peut être composée de caractères simples et/ou de caractères spéciaux des expressions régulières (ceux vus dans la partie consacrée à l’éditeur vi). Pour éviter que le shell n’interprète ces caractères, il est prudent d’encadrer le modèle par des guillemets simples ou doubles, ou de protéger les caractères spéciaux par un \.
Exemple
$ cat fic4
Cochon
Veau
Boeuf
rat
Rat
boeuf
Afficher les lignes du fichier commençant...
Autres commandes utilitaires
Linux dispose d’un très grand nombre de commandes utilitaires, en particulier pour gérer des fichiers. En voici quelques-unes.
1. Extraction d’une partie d’un chemin d’accès
La commande basename permet d’extraire la partie nom de fichier d’un chemin d’accès de fichier.
Exemple
$ basename /tmp/pba/liste
liste
La commande dirname effectue l’inverse, elle extrait la partie chemin d’accès, sans le nom de fichier.
Exemple
$ dirname /tmp/pba/liste
/tmp/pba
2. Comparaison de fichiers
Diverses commandes permettent de comparer le contenu de deux fichiers.
a. diff
La commande diff indique les différences entre deux fichiers spécifiés et les modifications à leur apporter pour que leur contenu soit identique.
Syntaxe
diff [-b] fic1 fic2
L’option -b permet d’ignorer les caractères blancs (blank).
La commande diff affiche des commandes de vi permettant de rendre les fichiers identiques. Le symbole < désigne le fichier fic1, le symbole > le fichier fic2.
Exemple
$ cat liste
Produit objet prix quantites
souris optique 30 15
dur 30giga 100 30
dur 70giga 150 30
disque zip 12 30
disque souple 10 30
ecran 15 150 20 ...
La gestion des processus
Tout programme en cours d’exécution sur un système Linux est associé à au moins un processus, géré par le noyau et inscrit dans une entrée de la table des processus, répertoriant ses différents attributs. Un processus Linux est toujours associé à un processus parent, l’ensemble des processus constituant donc une arborescence.
1. Attributs d’un processus
Voici une liste des principaux attributs d’un processus :
-
Son identifiant de processus PID (Process ID) : chaque processus est identifié par un numéro unique. Le premier processus est créé par le noyau, avec le PID 1 il s’agit en général du programme init ou de systemd.
-
L’identifiant de processus de son processus parent PPID (Parent Process ID) : un processus est toujours créé par un autre processus (sauf le processus initial, créé par le noyau), via l’appel système fork.
-
Un identifiant d’utilisateur UID (User ID) et un identifiant de groupe GID (Group ID) : correspond par défaut à l’UID et au GID du groupe principal de l’utilisateur qui a lancé le processus. Ces éléments déterminent les permissions d’accès aux objets du système (fichiers, répertoires, etc.). Les processus enfants héritent de ces informations.
-
Durée de traitement et priorité : la durée de traitement correspond au temps d’exécution écoulé depuis le dernier réveil du processus. Dans un environnement multitâche, le temps d’exécution est partagé entre les divers processus, et tous ne possèdent pas la même priorité. Les processus de plus haute priorité sont traités en premier. Lorsqu’un processus est inactif, sa priorité augmente afin d’avoir une chance d’être exécuté. Lorsqu’il est actif, sa priorité baisse afin de laisser sa place à un autre. C’est l’ordonnanceur de tâches du noyau qui gère les priorités et les temps d’exécution.
-
Répertoire courant : à son lancement, le répertoire courant (celui depuis lequel le processus a été lancé) est transmis au processus....
Plus loin avec le bash
Les programmes de type shell, et particulièrement le bash, propose des fonctionnalités très évoluées. Cette partie du chapitre présente certaines d’entre elles.
1. Les alias
Un alias est un raccourci d’une ligne de commande, déclaré dans le shell courant et n’existant que jusqu’à la fin de la session (c’est pourquoi les alias sont souvent définis dans les fichiers d’initialisation du shell). Il se définit avec la commande alias.
Syntaxe
Alias NomAlias='Ligne de commande'
Sans argument, la commande liste les alias disponibles.
Exemple
Liste des alias par défaut d’un compte utilisateur d’une distribution RHEL :
$ alias
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias xzegrep='xzegrep --color=auto'
alias xzfgrep='xzfgrep --color=auto'
alias xzgrep='xzgrep --color=auto'
alias zegrep='zegrep --color=auto'
alias zfgrep='zfgrep --color=auto'
alias zgrep='zgrep --color=auto'
Création d’un alias :
$ alias monls='ls -il'
$ monls /
total 28
30026...
Les variables
Une variable est un nom logique associé à un emplacement à l’intérieur d’une zone mémoire particulière d’un processus : son environnement. Le contenu d’une variable, le plus souvent une chaîne de caractères, est utilisable sur la ligne de commande ou par des programmes.
1. Nom de variable
Un nom de variable obéit à certaines règles :
-
Il est composé de lettres minuscules ou majuscules, de chiffres et du caractère souligné.
-
Il ne peut pas commencer par un chiffre (sauf les variables prédéfinies).
-
La taille maximale du nom est indéfinie.
2. Déclaration et affectation
Une variable est déclarée dès qu’une valeur lui est affectée. L’affectation est effectuée avec le signe =, sans espace avant ou après le signe.
Exemple
var=Bonjour
3. Accès et affichage
Pour accéder au contenu d’une variable, on place le caractère $ devant son nom. Quand le shell analyse une ligne de commande, il considère comme nom de variable la suite de caractères située entre le $ et le premier caractère ne pouvant figurer dans un nom de variable. Si une variable de ce nom existe, le shell remplace la chaîne $nomvar par son contenu, sinon par une chaîne nulle.
Exemple
Création et utilisation de la variable montmp :
$ montmp=/tmp/pba
$ cp fic $montmp
$ ls -l fic /tmp/pba
-rw-r--r--. 1 pba pba 8 15 mai 16:53 fic
-rw-r--r--. 1 pba pba 8 22 mai 21:35 /tmp/pba
La commande env affiche la liste des variables connues du shell courant et de ses processus enfants. La commande set sans argument affiche la liste de toutes les variables connues du shell courant (ainsi que d’autres types d’éléments).
Exemple
La variable créée dans l’exemple précédent est listée par set, pas par env :
$ env
SHELL=/bin/bash
HISTCONTROL=gnoredups
HISTSIZE=1000
HOSTNAME=srvrh
PWD=/home/pba
LOGNAME=pba
XDG_SESSION_TYPE=tty
MOTD_SHOWN=pam
HOME=/home/pba
LANG=fr_FR.UTF-8
...
$ env | grep montmp
$ set | grep montmp
montmp=/tmp/pba
Une variable peut contenir des caractères spéciaux (espace, point-virgule...
Configuration de bash
Selon son mode de démarrage, le shell exécute divers fichiers de configuration. Un fichier de configuration est un script shell, contenant une suite de commandes ayant pour but de configurer l’environnement de l’utilisateur.
1. Fichiers de configuration
Le shell bash peut être lancé dans plusieurs modes :
-
shell interactif de connexion (login shell)
-
shell lancé par un autre shell, explicitement ou pour exécuter un script
a. Shell de connexion
Le shell de connexion est lancé après la saisie du login et du mot de passe sur la console. C’est le programme dont le chemin d’accès est spécifié dans le dernier champ de la ligne du compte utilisateur dans /etc/passwd.
Dans ce mode, le bash exécute, s’ils existent et dans cet ordre, les fichiers suivants :
-
/etc/profile
-
/etc/profile/profile.d/*
-
$HOME/.bash_profile
-
$HOME/.bash_login
-
$HOME/.bashrc
À la déconnexion, il tente d’exécuter :
-
$HOME/.bash_logout
b. Shell simple
Un shell peut être lancé depuis un autre shell, soit en le spécifiant sur la ligne de commande, soit automatiquement à l’exécution d’un script.
Dans ce cas, il n’exécute qu’un seul fichier de configuration, s’il existe :
-
$HOME/.bashrc
Les shell autres que le bash fonctionnent avec les mêmes principes, mais...
Programmation shell
Le shell n’est pas qu’un simple interpréteur de commandes, il dispose d’un véritable langage de programmation avec notamment une gestion des variables, des tests et des boucles, des fonctions, etc.
1. Structure et exécution d’un script shell
Un script shell est un fichier texte contenant des lignes de commandes shell. Lors de son exécution, par un shell, chaque ligne est lue, interprétée et exécutée, comme s’il s’agissait d’une ligne de commande interactive.
Une ligne peut se composer de commandes internes ou externes, de commentaires ou être vide. Plusieurs instructions par lignes sont possibles, séparées par le caractère ; ou liées conditionnellement par && ou ||. Le ; est l’équivalent d’un saut de ligne. On peut également utiliser le caractère & pour exécuter une ligne en tâche de fond.
Avant que le shell n’exécute une ligne de commande, il l’analyse, l’interprète puis, s’il s’agit d’une commande externe, il cherche le chemin d’accès de son fichier exécutable.
Le shell demande alors l’exécution du fichier. Si les permissions d’accès de l’utilisateur associé au shell le permettent (droit x), un nouveau processus est créé pour exécuter le fichier. Dans le cas d’un fichier script, ce processus exécute un shell qui va lire le fichier script ligne à ligne et exécuter chaque ligne dans l’ordre du fichier.
La commande chmod permet de donner le droit d’exécution au propriétaire sur un fichier script.
Syntaxe
$ chmod u+x monscript
Pour demander l’exécution d’un fichier script, on peut spécifier son chemin d’accès, ou, s’il est placé dans un répertoire référencé par la variable PATH, spécifier son nom.
On peut également le faire exécuter explicitement par un shell enfant, auquel cas le droit de lecture sur le fichier suffit pour l’exécution.
Syntaxe
bash CheminScript
Exemple
Création et exécution d’un script shell :
$ vi monscript
echo début de mon script
date
who
echo fin de mon script ...
Multiplexeurs de terminal
Les outils screen et tmux permettent de gérer plusieurs fenêtres en mode caractère au sein d’un même terminal. Les exemples présentés s’appuient sur screen mais peuvent s’appliquer à tmux qui utilise la même syntaxe.
Ces outils logiciels offrent notamment les fonctionnalités suivantes :
-
Ouvrir plusieurs fenêtres shell depuis une seule connexion ssh
-
Maintenir des connexions ssh ouvertes en cas de problème réseau (reprise automatique)
-
Se déconnecter et se reconnecter à ses sessions shell et ssh de plusieurs endroits (et réseaux)
-
Lancer une commande shell de longue durée sans avoir à maintenir une session active
1. Utilisation
a. Installation et aide
L’installation s’effectue avec le paquet logiciel screen.
Une fois la commande screen lancée, on peut accéder à l’aide en appuyant successivement sur [Ctrl] a puis ?.
b. Fenêtres
La séquence [Ctrl] a c ouvre une nouvelle fenêtre de connexion. Les différentes fenêtres sont numérotées de 0 à n.
Pour passer à la fenêtre X, on utilise la séquence de touches [Ctrl] a X.
Les séquences [Ctrl] a n (next) et [Ctrl] a p (previous) permettent de passer à la fenêtre suivante ou précédente.
La commande...