Les 6 façons fondamentales dont les utilisateurs et les programmes interagissent via le terminal
- 12 janvier 2026
- 11 mins de lecture
- Concepts de programmation , Systèmes d'exploitation
Table des matières
Chaque programme communique. Il reçoit des données. Il produit des résultats.
Quand on débute, le terminal peut donner l’impression d’une boîte noire où des choses se produisent sans que l’on comprenne vraiment pourquoi.
Mais la réalité est simple : dans le terminal, il n’existe que six canaux de communication fondamentaux entre un programme et son utilisateur. Trois permettent à l’utilisateur de parler au programme (Terminal → Programme). Trois permettent au programme de répondre (Programme → Terminal).
Ensemble, ils expliquent comment les programmes en ligne de commande communiquent avec le terminal : stdin, stdout, stderr, les arguments, les variables d’environnement et les codes de sortie.
Cet article se concentre sur la communication orientée utilisateur, et non sur la communication générale entre processus comme les sockets ou la mémoire partagée.
Une fois ces mécanismes compris, la programmation devient plus mécanique que mystérieuse, et le débogage cesse d’être un jeu de devinettes.
Nous allons passer en revue les six, voir comment Linux (bash) et Windows (PowerShell) les gèrent, et construire un modèle mental clair à l’aide d’exemples.
Ces concepts s’appliquent à toute interface en ligne de commande (CLI), que vous utilisiez bash, zsh ou PowerShell.
​
Interactions statiques et dynamiques
Avant d’aller plus loin, une idée doit être bien claire :
Les interactions statiques ont lieu une seule fois par exécution.
Vous les fournissez avant le démarrage du programme, et elles restent identiques pendant toute son exécution. Et le programme envoie un dernier message après sa fin : son code de sortie.
Il s’agit de :
- Arguments en ligne de commande (utilisateur → programme, une seule fois au démarrage)
- Variables d’environnement (utilisateur → programme, une seule fois au démarrage)
- Code de sortie (programme → utilisateur, une seule fois à la fin)
Les interactions dynamiques ont lieu pendant l’exécution du programme.
Elles permettent un échange continu.
Il s’agit de :
- stdin (utilisateur → programme)
- stdout (programme → utilisateur, messages attendus)
- stderr (programme → utilisateur, messages inattendus)
Les six sont établies par le système d’exploitation lors de la création du processus ; le terminal n’est qu’un point de terminaison possible.
​
1. Arguments en ligne de commande (entrée statique)
Les arguments en ligne de commande permettent à l’utilisateur de transmettre une information au programme une seule fois, au moment de son lancement.
- Linux
- Windows
Linux (bash) :
1user@host:~/$ ./greeter Alice
2Hello Alice!
Windows (PowerShell) :
1PS C:\Users> .\greeter.exe Alice
2Hello Alice!
Les mots placés après le nom du programme sont les arguments (ici, Alice).
Ils servent à fournir au programme les informations nécessaires pour décider comment il doit s’exécuter.
Le programme les reçoit avant même de commencer son exécution.
Ils sont copiés en mémoire dans le processus, généralement sous forme d’une liste de chaînes de caractères, dès le démarrage.
Cela est directement lié à ce qui se produit lorsqu’un binaire devient un processus. Voir mon article Comment un binaire devient un processus en cours d’exécution.
Du point de vue du programme, ils sont immuables pendant toute l’exécution.
Tip
Les arguments en ligne de commande sont idéaux pour les modes optionnels, les noms de fichiers ou des valeurs ponctuelles fournies par l’utilisateur.
​
2. Variables d’environnement (entrée statique)
Les variables d’environnement agissent comme des réglages de configuration. Elles sont elles aussi transmises au programme une seule fois, au moment de son lancement.
On peut les définir ainsi :
- Linux
- Windows
Linux (bash) :
1user@host:~/$ export NAME=Alice
2user@host:~/$ ./greeter
3Hello Alice!
Windows (PowerShell) :
1PS C:\Users> $env:NAME="Alice"
2PS C:\Users> .\greeter.exe
3Hello Alice!
Si vous définissez une variable dans le shell, elle remplace les valeurs par défaut que le programme aurait autrement vues. Le programme reçoit exactement ce que le processus parent lui transmet au démarrage.
Les variables d’environnement sont héritées : un programme reçoit une copie de l’environnement de son parent, pas un environnement partagé.
Arguments + variables d’environnement constituent l’ensemble des entrées statiques.
Les variables d’environnement servent généralement à une configuration plus globale, souvent partagée entre plusieurs programmes, tandis que les arguments sont spécifiques à une invocation donnée.
Note
En pratique, les variables d’environnement sont particulièrement utiles pour des valeurs qui changent rarement sur une machine donnée.
Je les ai souvent utilisées pour éviter des arguments en ligne de commande longs et répétitifs, par exemple pour des chemins ou des identifiants faisant partie de la configuration de l’utilisateur.
​
3. stdout – La voix principale du programme (sortie dynamique)
La sortie standard (stdout) est la voix normale du programme.
Elle affiche les informations attendues : résultats, messages, journaux, invites.
1user@host:~/$ find
2./.bash_logout
3./.bashrc
4./.bash_history
5./.gitconfig
Mais voici le point clé : stdout est généralement bufferisée, et la stratégie de bufferisation dépend de ce à quoi elle est connectée.
Quand stdout est connectée à un terminal, elle est le plus souvent bufferisée par ligne.
C’est pourquoi l’affichage d’un retour à la ligne (\n) rend souvent le texte visible immédiatement.
On peut comparer cela au bouton Envoyer d’une application de messagerie : le message existe, mais il ne part pas tant que vous n’appuyez pas dessus.
Lorsque stdout est redirigée vers un fichier ou un pipe, son comportement change.
Le programme peut accumuler de plus gros blocs de texte avant de les écrire.
C’est ce que signifie une bufferisation par blocs : la sortie est conservée jusqu’à ce que le tampon soit plein.
Ceci est un tampon interne complet, pas un simple retour à la ligne ou un appel d’écriture.
Tant qu’un flush n’a pas lieu, le texte reste généralement dans le tampon.
Pour écrire sur stdout, le programme doit écrire sur le descripteur de fichier 1.
Sous Windows, cela est géré via STD_OUTPUT_HANDLE, bien que de nombreux environnements émulent le descripteur standard 1 pour assurer la compatibilité multiplateforme.
Tip
Les pipes fonctionnent en connectant directement le stdout d’un programme au stdin d’un autre.
C’est ainsi que des workflows complexes sont construits à partir d’outils simples.
1cat file.txt | grep "search term"
Warning
Il m’est déjà arrivé de perdre du temps à déboguer un programme parce que j’avais affiché un message d’erreur sur stdout au lieu de stderr.
Comme stdout était bufferisée par blocs et jamais flushée avant la fin abrupte du programme, le message n’apparaissait jamais.
En l’écrivant sur stderr, il s’affichait immédiatement.
C’est un bug qui n’a de sens que lorsqu’on comprend la bufferisation.
​
4. stderr – La « voix d’urgence » du programme (sortie dynamique)
La sortie d’erreur standard (stderr) est destinée aux situations inattendues.
Erreurs. Avertissements. Tout ce qui ne fait pas partie du flux normal.
1user@host:~/$ grep
2Usage: grep [OPTION]... PATTERNS [FILE]...
3Try 'grep --help' for more information.
Par défaut, stderr est généralement non bufferisée ou très peu bufferisée, ce qui explique pourquoi les messages d’erreur apparaissent souvent immédiatement, même lorsque la sortie normale est retardée.
stdout et stderr sont séparées ; le terminal n’en a pas conscience
Les deux flux correspondent à des descripteurs de fichiers différents (stdout est 1, stderr est 2); il en va de même pour les handles Windows.
Cette séparation permet par exemple :
1./program 1>output.txt 2>errors.txt
Au démarrage d’un programme, le shell connecte généralement les deux au même périphérique de terminal.
Une fois que le texte atteint le terminal, ce n’est plus qu’un flux d’octets.
Le terminal reçoit uniquement des octets ; il ne sait pas s’ils proviennent de stdout ou de stderr.
Warning
Lorsque stdout et stderr écrivent simultanément vers le terminal, leurs sorties peuvent s’entrelacer de manière inattendue.
Sous Windows, PowerShell expose les mêmes concepts, même si l’implémentation et les API sous-jacentes diffèrent.
Deux voix, deux canaux, un seul écran.
Les programmes à interface graphique (GUI) disposent souvent de ces flux eux aussi, mais ils ne sont pas visibles ni connectés à un terminal par défaut.
​
5. stdin – Le flux d’entrée du programme (entrée dynamique)
stdin est le moyen par lequel un programme reçoit des informations pendant son exécution.
Du point de vue du système d’exploitation, stdin est simplement un descripteur de fichier comme un autre.
1user@host:~/$ read name
2BuildSoftwareSystems
3user@host:~/$ echo "My name is $name"
4My name is BuildSoftwareSystems
Comment l’entrée du terminal arrive réellement sur stdin
Ce que vous tapez dans le terminal n’est pas envoyé au programme tant que vous n’appuyez pas sur Entrée.
Jusque-là, le terminal conserve le texte.
Appuyer sur Entrée est le signal qui transmet la ligne complète au programme via stdin.
stdin est connecté au descripteur de fichier 0 (il en va de même pour le STD_INPUT_HANDLE sous Windows).
Il est possible de configurer le terminal pour envoyer chaque frappe immédiatement (mode brut / keystroke), mais par défaut il attend la touche Entrée.
La bufferisation de la sortie est contrôlée par le flux de sortie du programme. La bufferisation de l’entrée est contrôlée par le terminal.
stdin ne provient pas forcément d’un clavier.
Il peut aussi provenir d’un fichier, d’un pipe ou d’un autre programme.
Plus fondamentalement, un programme peut lire une entrée et produire une sortie en même temps parce que stdin est séparé de stdout et de stderr.
Info
stdin, stdout et stderr sont-ils réservés aux terminaux ?
Non. Ce sont des concepts du système d’exploitation que les terminaux connectent fréquemment, mais n’importe quel processus peut les fournir lors du lancement d’un autre programme.
​
6. Codes de sortie – Le dernier message du programme
Lorsqu’un programme se termine, il renvoie un code de sortie numérique.
- Sur les systèmes de type Unix, il est conventionnellement compris entre 0 et 255.
- Sous Windows, les programmes natifs renvoient des entiers sur 32 bits (donc bien plus grands), mais cela ne fonctionne que pour les applications console natives (
.exe,.bat,.cmd).
Cela ne fonctionne généralement pas pour les applications graphiques (comme Notepad) ni pour les cmdlets PowerShell intégrées (commels).
Ce nombre est stocké dans les métadonnées du processus (le Process Control Block, ou PCB).
Par convention :
0→ tout s’est bien passé1→ une erreur est survenue (échec général simple)- autres valeurs → significations définies par le programme
- Linux
- Windows
Vérification sous bash :
1user@host:~/$ true
2user@host:~/$ echo $?
30
Vérification sous PowerShell :
1PS C:\Users> whoami
2host\user
3PS C:\Users> echo $LASTEXITCODE
40
Le shell le récupère et le rend accessible via $? sous Bash ou $LASTEXITCODE sous PowerShell.
Il peut aussi être récupéré de manière programmatique par des processus parents.
Info
Sous Windows PowerShell, pour les applications graphiques (comme Notepad) ou les cmdlets intégrées (comme ls ou Get-Item), utilisez $? pour vérifier le succès ou l’échec.
C’est le dernier mot du programme avant que le contrôle ne revienne à celui qui l’a lancé (par exemple le shell).
Bulletin d'information
Abonnez-vous à notre bulletin d'information et restez informé(e).
​
Comment stdin, stdout et stderr fonctionnent ensemble
La plupart des outils en ligne de commande sont petits et simples parce qu’ils n’ont pas besoin de se connaître entre eux.
Un programme écrit ses résultats sur stdout, un autre les lit depuis stdin, et les erreurs passent par stderr.
La redirection et les pipes permettent au shell de relier ces flux, tandis que les codes de sortie indiquent à l’appelant si toute la chaîne a réussi ou échoué.
C’est cette conception qui permet de créer des workflows complexes en combinant de petits outils plutôt qu’en écrivant un programme monolithique.
​
Pourquoi c’est important
1./build.sh > build.log 2>&1
2if [ $? -ne 0 ]; then
3 echo "Build failed"
4fi
Lorsqu’on automatise des tâches, on souhaite souvent séparer la sortie normale des erreurs.
La redirection de stdout et stderr permet de contrôler ce qui est journalisé, ignoré ou affiché à l’utilisateur.
Cette séparation est ce qui rend les outils fiables lorsqu’ils sont combinés dans des scripts et des pipelines.
Les codes de sortie relient l’ensemble. Ils permettent aux scripts et aux programmes appelants de savoir si une commande a réussi ou échoué, et d’agir en conséquence.
Si vous ne deviez retenir qu’une chose à propos du terminal, retenez celle-ci :
- L’automatisation, le scripting et les outils reposent sur ces canaux.
- Chaque programme en ligne de commande démarre avec ces canaux disponibles, même s’il ne les utilise pas explicitement.
​
Conclusion
Si vous comprenez ces six interactions, vous comprenez l’ossature de tout programme en ligne de commande, qu’il soit écrit en C, Rust, Python ou autre.
Elles sont simples, mais elles constituent un modèle mental complet de la façon dont les humains et les programmes communiquent via le terminal.
Maîtrisez-les dès maintenant, et vous comprendrez non seulement ce que font les programmes en ligne de commande, mais aussi comment ils s’assemblent entre eux.