Skip to content

Variables d'environnement et PATH

💡 Guide d'apprentissage : Chaque fois que vous saisissez git ou python dans le terminal, le systeme doit trouver ou se trouve ce programme. Chaque fois que votre code appelle une API de grand modele linguistique, le programme doit savoir quelle cle utiliser. Derriere ces deux taches se cache le meme mecanisme — les variables d'environnement.


0. Chaque programme emporte avec lui un ensemble de configurations

Chaque programme en cours d'execution possede un ensemble de configurations "cle=valeur" appelees variables d'environnement. Le programme peut lire ces configurations a tout moment pour connaitre l'environnement d'execution actuel.

Cliquez sur n'importe quelle variable dans la liste ci-dessous pour "consulter" sa valeur dans le terminal :

Environment Variable BrowserClick any variable row to inspect its value and purpose in the terminal
VariableExample value
HOME/Users/alice
USERalice
SHELL/bin/zsh
PATH/usr/local/bin:/usr/bin:/bin
PWD/Users/alice/projects
LANGen_US.UTF-8
NODE_ENVdevelopment
OPENAI_API_KEYsk-••••••••••••••••
bash
← Click any variable on the left to inspect it
$
Core concept:Environment variables are key=value configuration owned by each process. A program inherits a copy from its parent process at startup. You can inspect them with echo $VARIABLE and set them with export KEY=value.

1. PATH : Comment le Shell trouve les commandes que vous saisissez

PATH est une variable d'environnement speciale qui stocke une liste de chemins de repertoires (separes par des deux-points). Lorsque vous saisissez git, le Shell parcourt ces repertoires dans l'ordre pour trouver un fichier executable nomme git — il s'arrete des qu'il trouve le premier.

bash
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Selectionnez une commande et observez le processus de recherche repertoire par repertoire du Shell :

PATH Search ProcessEnter a command name and see how the shell searches directories
Choose command:
Current PATH:
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
/usr/local/bin
Waiting
/usr/bin
Waiting
/bin
Waiting
/usr/sbin
Waiting
/sbin
Waiting
Core mechanism:After the shell receives a command name, it searches directories in PATH order. The first match wins and the search stops. That makes PATH order important: earlier directories have higher priority.

Trois regles cles :

  • Plus un repertoire est vers le debut du PATH, plus sa priorite est elevee
  • La recherche s'arrete au premier trouve, sans continuer
  • Si aucun repertoire ne contient le programme → command not found

2. Pourquoi faut-il redemarrer le terminal apres l'installation d'un outil ?

Lors de l'installation d'outils comme nvm, Homebrew ou conda, le script d'installation ajoute automatiquement une ligne a ~/.zshrc pour inclure son propre repertoire dans le PATH :

bash
# Contenu ecrit automatiquement par le script d'installation (exemple)
export PATH="/usr/local/opt/python@3.12/bin:$PATH"

Cette ligne de code n'est executee qu'au demarrage d'un nouveau Shell. Les fenetres de terminal deja ouvertes ne sont pas affectees, donc :

bash
# Egalement efficace sans redemarrage
source ~/.zshrc

Situations frequentes avec les outils de developpement IA :

bash
# Ollama / pipx affichent command not found apres l'installation
which ollama          # Trouver l'emplacement reelle de l'installation

# Chemin des outils CLI installes via pip (a ajouter au PATH)
# macOS : ~/Library/Python/3.x/bin
# Linux : ~/.local/bin
export PATH="$PATH:$HOME/.local/bin"

# Recommande : installer les outils CLI avec pipx, gere le PATH automatiquement
pipx install aider-chat

3. Portee des variables : Qui peut voir cette variable ?

Les variables d'environnement ne sont pas diffusees a tous les programmes — chaque processus detient sa propre copie, heritee du processus parent. Modifier sa propre copie n'affecte pas le processus parent.

Le diagramme ci-dessous montre trois niveaux. Exportez une nouvelle variable au "niveau utilisateur" et verifiez si elle apparait au "niveau processus" :

Three Levels of Environment VariablesVariables flow one way from outer scopes to inner scopes; child processes inherit a copy from parents
🖥️
System level /etc/environment
Visible to all users and processes; configured by an administrator
PATH=/usr/local/bin:/usr/bin:/bin
LANG=zh_CN.UTF-8
TZ=Asia/Shanghai
▼ Child process inherits the parent environment
👤
User level ~/.zshrc
Affects only the current user and is loaded when the login shell starts
HOME=/Users/alice
SHELL=/bin/zsh
NVM_DIR=$HOME/.nvm
=
▼ Start a child process, such as node app.js
⚙️
Process level (currently running program)
Inherits variables from upper levels, disappears on exit, and does not modify the parent process
PATH=/usr/local/bin:/usr/bin:/bin
LANG=zh_CN.UTF-8
TZ=Asia/Shanghai
HOME=/Users/alice
SHELL=/bin/zsh
NVM_DIR=$HOME/.nvm
NODE_ENV=development
PORT=3000
One-way flow:Variables are inherited downward only. Changing a variable in a child process does not affect its parent. Variables set with export in a terminal also disappear when that terminal closes.

4. export : Determine si un processus enfant peut lire cette variable

Lors de la definition d'une variable, ajouter ou non export fait une difference fondamentale :

export Decides Whether Child Processes Can See a VariableToggle the switch and observe whether the child process can read a variable set by the parent
Parent process (Shell)
$MY_VAR="hello"
$echo $MY_VAR
hello
$bash -c 'echo $MY_VAR'
Start child process
Variable not inherited
Child process (bash -c ...)
$echo $MY_VAR
(empty output)
#A child process cannot modify parent variables
Without export: The variable exists only in the current shell, so the child process reads an empty string.

Pour qu'une variable persiste entre les sessions, ecrivez la commande export dans un fichier de configuration :

bash
# macOS (zsh)
echo 'export MY_VAR="value"' >> ~/.zshrc
source ~/.zshrc       # Effectif immediatement, pas besoin de redemarrer le terminal

# Linux (bash)
echo 'export MY_VAR="value"' >> ~/.bashrc
source ~/.bashrc

5. Cles API : Ne doivent jamais etre ecrites dans le code

Lorsque vous appelez des API comme OpenAI, Anthropic ou DeepSeek, la cle est votre "piece d'identite + carte de credit". Si elle est divulgue, d'autres peuvent utiliser votre quota et les frais sont a votre charge.

L'erreur la plus courante est d'ecrire la cle directement dans le code :

Hard-coded Keys vs Environment VariablesThe same feature, two implementations, completely different security outcomes
Dangerous: key written in code
# Python
import openai
 
client = openai.OpenAI(
api_key="sk-proj-abc123..."
)
💀After git push, the key is public on GitHub
💀Crawlers can find it quickly and generate costs
💀GitHub Secret Scanner may revoke the key automatically
💀Deleting the commit is not enough because Git history keeps it
Correct: read from environment variable
# Python
import openai, os
 
client = openai.OpenAI(
api_key=os.environ.get("OPENAI_API_KEY")
)
The code contains no secret and can be open-sourced safely
Development, testing, and production can use different keys
If a key leaks, regenerate it without changing code
Team members can use separate keys without affecting each other
Golden rule:A secret string in code means the secret is already leaked. GitHub Secret Scanner can detect prefixes such as sk- shortly after a push and notify providers to revoke them. Even if you delete the commit, Git history still contains it.

6. Developpement local : Gerer les cles avec un fichier .env

En developpement local, stockez les cles dans un fichier .env a la racine du projet. Le code les lit via la bibliotheque dotenv. .env doit imperativement etre ajoute a .gitignore et ne jamais etre commite dans Git.

Ecrivez la configuration a gauche et lisez-la a droite — changez de langue pour voir deux approches differentes :

.env File + Code ReadingConfiguration on the left, code on the right; the variable name is the only link
📄 .env Do not commit
# Local development config, do not commit to Git
OPENAI_API_KEY=sk-proj-abc123...
DATABASE_URL=postgresql://localhost/dev
PORT=3000
NODE_ENV=development
📋 .env.example Can commit
# Copy to .env and fill in real values
OPENAI_API_KEY=(leave empty)
DATABASE_URL=(leave empty)
PORT=(leave empty)
NODE_ENV=(leave empty)
💻 main.py
# pip install python-dotenv openai
from dotenv import load_dotenv
import os, openai
 
load_dotenv() # Read .env file
 
client = openai.OpenAI(
api_key=os.environ.get("OPENAI_API_KEY")
)
 
db = os.environ.get("DATABASE_URL")
port = int(os.environ.get("PORT", 8000))
Values actually read by the program
OPENAI_API_KEYsk-proj-abc123...
DATABASE_URLpostgresql://localhost/dev
PORT3000
Workflow:load_dotenv() / import 'dotenv/config' reads the .env file at startup, injects its key-value pairs into the process environment, and the code reads them with os.environ or process.env. The two sides are connected only by variable names.

7. Environnement de production : Laisser la plateforme d'execution injecter les cles

.env est un outil de commodite pour la phase de developpement. Sur les serveurs et les plateformes cloud, c'est l'environnement d'execution qui doit etre responsable de l'injection des cles — le code lui-meme ne doit pas savoir ou les cles sont stockees :

How Production Injects Secrets.env is a development convenience; servers should not rely on it
/etc/systemd/system/myapp.service
# Recommended: use a separate secret file with controlled permissions
[Service]
EnvironmentFile=/etc/myapp/secrets.env
ExecStart=/usr/bin/node /app/index.js
# Set file permissions so only the owner can read it
sudo chmod 600 /etc/myapp/secrets.env
sudo chown deploy:deploy /etc/myapp/secrets.env
# Reload configuration and restart the service
sudo systemctl daemon-reload
sudo systemctl restart myapp
After chmod 600, only the deploy user can read the secret file; other accounts cannot access it
Secrets are separated from code, so rotating a key does not require redeploying code
Avoid writing Environment="KEY=val" directly in the systemd file; it requires reloads and leaves plaintext in config
Principle:.env files are convenient for local development. In production, the runtime platform should inject environment variables, while application code stays unaware of where secrets live or how they arrived.

8. Resolution de problemes en pratique

command not found

bash
# Etape 1 : Verifier si le programme est dans le PATH
which python3         # Une sortie signifie qu'il a ete trouve

# Etape 2 : Trouver l'emplacement reel du programme (macOS)
brew list python | grep bin

# Etape 3 : Ajouter le repertoire au PATH
export PATH="/chemin/trouve:$PATH"
source ~/.zshrc       # Apres avoir ecrit dans le fichier de configuration, executer source

Deux versions installees, mais ce n'est pas celle voulue qui est utilisee

bash
which python
# /usr/bin/python ← Ancienne version systeme, plus haut dans le PATH

# Placer le repertoire de la nouvelle version en debut de PATH
export PATH="/usr/local/bin:$PATH"

which python
# /usr/local/bin/python ← Nouvelle version, maintenant prioritaire

La variable est bien definie mais le programme ne la lit pas

CauseSolution
Oubli de exportAjouter export et reessayer
Modification de ~/.zshrc sans effetsource ~/.zshrc
Utilisation de .env mais dotenv non installepip install python-dotenv / npm install dotenv
Sur le serveur, effectif uniquement dans la session SSHUtiliser EnvironmentFile de systemd a la place

Glossaire

TermeSignification
PATHStocke la liste des repertoires ou le Shell recherche les fichiers executables, separes par des deux-points, l'ordre determine la priorite
exportMarque une variable comme transmissible, les processus enfants recoivent automatiquement une copie au demarrage
sourceRe-execute un fichier de configuration dans le Shell actuel, rendant les modifications immediatement effectives
whichAffiche le chemin du fichier executable correspondant a une commande (resultat de la recherche dans le PATH)
.envFichier de configuration local du projet, stocke les cles de developpement, doit imperativement etre ajoute a .gitignore
.env.exampleModele avec des noms de variables complets mais des valeurs vides, peut etre commite securitairement dans Git
chmod 600Permissions de fichier : seul le proprietaire peut lire et ecrire, adapte pour proteger les fichiers de cles
Secret ScannerFonctionnalite des plateformes comme GitHub qui scanne automatiquement les fuites de cles et notifie le fournisseur pour les revoquer