infra / linux-bash
Variables d'environnement et PATH
Explication
En bash, une variable "normale" n'existe que dans le shell où elle est créée : si tu lances un autre programme depuis ce shell, ce programme ne la voit pas du tout. export change cette règle en la transformant en variable d'environnement, transmise automatiquement à tous les processus lancés ensuite.
Ce que vous allez apprendre
- Distinguer une variable de shell locale d'une variable d'environnement exportée
- Comprendre comment bash retrouve un exécutable grâce à la variable
PATH - Diagnostiquer un conflit de version d'outil causé par l'ordre des dossiers du
PATH - Choisir le bon fichier (
~/.bashrc,~/.profile,/etc/environment) pour rendre une variable permanente - Éviter le risque de sécurité d'un
PATHmal ordonné
Dans quel contexte ?
Un développeur a installé Python 3.11 via un gestionnaire de versions personnalisé dans ~/.local/bin, mais quand il tape python3 --version dans un script cron, c'est toujours l'ancienne version système 3.9 qui répond. Le problème ne vient ni de l'installation ni du script : c'est l'ordre du PATH qui détermine quel python3 est trouvé en premier, et cron n'utilise pas le même PATH qu'un terminal interactif.
Une fois cette idée acquise, voyons un cas concret : la variable PATH
Quand tu tapes ls, bash ne devine pas où se trouve ce programme par magie. Il consulte la variable PATH, qui liste, dans l'ordre, tous les dossiers où chercher un exécutable de ce nom, et s'arrête au tout premier trouvé.
Ce mécanisme explique un phénomène parfois déroutant : installer deux versions d'un même outil peut créer des conflits, car celle qui est trouvée en premier "gagne", même si ce n'est pas celle que tu voulais utiliser.
| Fichier | Portée | Exécuté quand |
|---|---|---|
~/.bashrc | Un seul utilisateur | À chaque nouveau terminal interactif |
~/.bash_profile / ~/.profile | Un seul utilisateur | Uniquement à la connexion (login shell) |
/etc/environment | Toute la machine | Au login, pour tous les utilisateurs |
~/.bashrc, ~/.bash_profile, /etc/environment : cette multiplicité de fichiers déroute souvent les débutants au premier abord. Il suffit en fait de retenir deux critères pour s'y retrouver : la portée (un utilisateur ou toute la machine) et le moment d'exécution (chaque terminal, ou seulement la connexion).
Prérequis
Connaître les bases du scripting bash (variables, echo) vues dans la leçon précédente aide à comprendre pourquoi export change le comportement d'une variable pour les processus enfants.
Il reste une question pratique : bien choisir où définir ces variables
Bien choisir le bon fichier évite des variables qui "ne marchent pas" alors qu'elles ont pourtant été définies quelque part — un classique quand une variable définie dans ~/.bashrc n'apparaît pas dans une tâche cron, qui ne charge pas ce fichier.
Piège dangereux
Ajouter un dossier personnel AVANT les dossiers système dans le PATH (export PATH="$HOME/bin:$PATH") peut sembler pratique, mais cela permet aussi à n'importe quel fichier de ce dossier de "masquer" une commande système du même nom — un vrai risque de sécurité si ce dossier n'est pas bien contrôlé (par exemple, un faux ls malveillant placé dans ~/bin).
Maintenant que tu sais comment circulent les variables et comment bash retrouve tes commandes, tu es prêt pour la suite logique : combiner plusieurs commandes ensemble grâce aux redirections et aux pipes.
Commandes & code
Variables d'environnement et PATH
# Variable de shell (locale) vs variable d'environnement (héritée par les processus enfants)
ma_variable="valeur" # visible uniquement dans ce shell
export MA_VARIABLE="valeur" # visible aussi par les programmes lancés depuis ce shell
env # liste toutes les variables d'environnement
printenv PATH # affiche une variable précise
echo "$HOME $USER $SHELL $LANG" # variables prédéfinies courantes
# PATH : liste des dossiers où bash cherche les exécutables, séparés par ":"
echo "$PATH"
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
which python3 # chemin absolu du binaire trouvé en premier dans le PATH
type -a python3 # liste TOUS les emplacements trouvés (utile en cas de conflit de version)
# Ajouter un dossier au PATH pour la session courante
export PATH="$HOME/bin:$PATH" # ajoute en priorité (recherché en premier)
export PATH="$PATH:/opt/monapp/bin" # ajoute en dernier (recherché en dernier)
# Rendre un changement permanent
# ~/.bashrc -> exécuté à chaque nouveau shell interactif (le plus courant)
# ~/.bash_profile / ~/.profile -> exécuté à la connexion (login shell)
# /etc/environment -> variables globales pour tous les utilisateurs (pas de logique shell ici)
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc # recharge sans avoir à rouvrir un terminal
# Variables utiles à connaître en scripting
echo "$?" # code de sortie de la dernière commande
echo "$$" # PID du shell courant
echo "$!" # PID du dernier process lancé en arrière-plan
echo "$OLDPWD" # répertoire précédent
# unset supprime une variable
unset MA_VARIABLE
# Variable locale à UNE SEULE commande (pas d'export permanent)
DEBUG=true ./mon_script.sh
# Ordre de résolution du PATH : bash cherche de gauche à droite et s'arrête au premier match
# -> attention aux dossiers custom placés AVANT /usr/bin qui peuvent masquer des binaires systèmeRésumé
exportrend une variable visible par les processus enfants, une variable locale ne l'est pas.PATHdétermine où bash cherche les commandes ; l'ordre des dossiers compte.~/.bashrcpour un utilisateur,/etc/environmentpour toute la machine.
Exercices pratiques
Mission : élucider un conflit de version Python entre terminal et cron
Objectif : Diagnostiquer un conflit d'ordre dans le PATH, puis expliquer pourquoi le même script se comporte différemment sous cron.
Contexte
Un développeur a installé Python 3.11 dans ~/.local/bin. Dans son terminal, python3 --version affiche bien 3.11. Mais le même script, lancé automatiquement par une tâche cron, continue d'utiliser l'ancienne version système 3.9 — sans qu'il ait touché à la crontab récemment.